We have a need to use nested transactions in our application. We are using JBoss 7.4, Spring Boot and Postgres.
I’ve tried some things I’ll document below, but I’m still getting this exception:
org.springframework.transaction.NestedTransactionNotSupportedException: JTA implementation does not support nested transactions
Based on some investigation I’ve done, JBoss / Wildfly does not support nested transactions out of the box. To get nested transaction support you must configure JBoss to use JTS. Below is the configuration I used to setup JTS and the datasource.
From the CLI I used the following commands to configure a node ID,
turn on IIOP full transactions, turn on JTS:
/system-property=jboss.tx.node.id:add(value="Node1234")
/subsystem=iiop-openjdk:write-attribute(name=transactions,value=full)
/subsystem=transactions:write-attribute(name=jts,value=true)
/subsystem=transactions:write-attribute(name=node-identifier,value="${jboss.tx.node.id}")
That results in the following configuration:
<system-properties>
<property name="jboss.tx.node.id" value="Node1234"/>
</system-properties>
...
<subsystem xmlns="urn:jboss:domain:iiop-openjdk:2.1">
<orb socket-binding="iiop"/>
<initializers security="identity" transactions="full"/>
<security server-requires-ssl="false" client-requires-ssl="false"/>
</subsystem>
...
<subsystem xmlns="urn:jboss:domain:transactions:6.0">
<core-environment node-identifier="${jboss.tx.node.id}">
<process-id>
<uuid/>
</process-id>
</core-environment>
<recovery-environment socket-binding="txn-recovery-environment" status-socket-binding="txn-status-manager"/>
<coordinator-environment statistics-enabled="${wildfly.transactions.statistics-enabled:${wildfly.statistics-enabled:false}}"/>
<object-store path="tx-object-store" relative-to="jboss.server.data.dir"/>
<jts/>
</subsystem>
I have my datasource configured as:
<xa-datasource jndi-name="java:/myDS" pool-name="myDS" use-ccm="false">
<xa-datasource-property name="URL">
jdbc:postgresql://myServer/myDB
</xa-datasource-property>
<driver>postgresql</driver>
<security>
<user-name>someuser</user-name>
<password>somepassword</password>
</security>
</xa-datasource>
And my driver setup like this:
<drivers>
<driver name="postgresql" module="org.postgresql">
<xa-datasource-class>org.postgresql.xa.PGXADataSource</xa-datasource-class>
</driver>
</drivers>
I wrote a quick little service class to test it that looks like this…
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Service
public class NestedTransService {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
NestedTransService self;
@Transactional
public void doSomeWork() {
logger.info("******** I'm doing some work in the outer transaction!");
self.doSomeSubWork();
}
@Transactional(propagation = Propagation.NESTED)
public void doSomeSubWork() {
logger.info("****** Now I'm doing done work in the nested transaction");
}
}
It fails on the call to self.doSomeSubWork() with:
20:33:18,755 ERROR [com.myOrganization.GlobalExceptionHandler] (default task-1) stacktrace: org.springframework.transaction.NestedTransactionNotSupportedException: JTA implementation does not support nested transactions; nested exception is javax.transaction.NotSupportedException: WFTXN0001: A transaction is already in progress
at deployment.my-app.war//org.springframework.transaction.jta.JtaTransactionManager.doBegin(JtaTransactionManager.java:852)
at deployment.my-app.war//org.springframework.transaction.support.AbstractPlatformTransactionManager.startTransaction(AbstractPlatformTransactionManager.java:400)
at deployment.my-app.war//org.springframework.transaction.support.AbstractPlatformTransactionManager.handleExistingTransaction(AbstractPlatformTransactionManager.java:464)
at deployment.my-app.war//org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:352)
at deployment.my-app.war//org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:574)
at deployment.my-app.war//org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:361)
at deployment.my-app.war//org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:118)
at deployment.my-app.war//org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at deployment.my-app.war//org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
at deployment.my-app.war//org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691)
at deployment.my-app.war//com.myOrganization.NestedTransService$$EnhancerBySpringCGLIB$$a710dce3.doSomeInteriorWork(<generated>)
at deployment.my-app.war//com.myOrganization.NestedTransService.doSomeWork(NestedTransService.java:21)
at deployment.my-app.war//com.myOrganization.NestedTransService$$FastClassBySpringCGLIB$$3fbb8763.invoke(<generated>)
at deployment.my-app.war//org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at deployment.my-app.war//org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771)
at deployment.my-app.war//org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at deployment.my-app.war//org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
at deployment.my-app.war//org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:367)
at deployment.my-app.war//org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:118)
at deployment.my-app.war//org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at deployment.my-app.war//org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
at deployment.my-app.war//org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691)
at deployment.my-app.war//com.myOrganization.NestedTransService$$EnhancerBySpringCGLIB$$a710dce3.doSomeWork(<generated>)
at deployment.my-app.war//com.myOrganization.NestedTransController.doIt(NestedTransController.java:24)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at deployment.my-app.war//org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
at deployment.my-app.war//org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
at deployment.my-app.war//org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)
at deployment.my-app.war//org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:878)
at deployment.my-app.war//org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:792)
at deployment.my-app.war//org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at deployment.my-app.war//org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
at deployment.my-app.war//org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
at deployment.my-app.war//org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at deployment.my-app.war//org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
at [email protected]//javax.servlet.http.HttpServlet.service(HttpServlet.java:503)
at deployment.my-app.war//org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at [email protected]//javax.servlet.http.HttpServlet.service(HttpServlet.java:590)
at [email protected]//io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74)
at [email protected]//io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129)
at deployment.my-app.war//com.myOrganization.FilterRequest.doFilter(FilterRequest.java:132)
at [email protected]//io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
at [email protected]//io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
at deployment.my-app.war//org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at deployment.my-app.war//org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at [email protected]//io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
at [email protected]//io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
at deployment.my-app.war//org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at deployment.my-app.war//org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at [email protected]//io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
at [email protected]//io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
at deployment.my-app.war//org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at deployment.my-app.war//org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at [email protected]//io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
at [email protected]//io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
at deployment.my-app.war//com.myOrganization.FilterRequest.doFilter(FilterRequest.java:132)
at [email protected]//io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
at [email protected]//io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
at [email protected]//io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
at [email protected]//io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
at [email protected]//io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
at [email protected]//io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
at [email protected]//org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)
at [email protected]//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at [email protected]//io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:68)
at [email protected]//io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:117)
at [email protected]//io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
at [email protected]//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at [email protected]//io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
at [email protected]//io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
at [email protected]//io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
at [email protected]//io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
at [email protected]//io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50)
at [email protected]//io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
at [email protected]//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at [email protected]//org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
at [email protected]//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at [email protected]//org.wildfly.extension.undertow.deployment.GlobalRequestControllerHandler.handleRequest(GlobalRequestControllerHandler.java:68)
at [email protected]//io.undertow.servlet.handlers.SendErrorPageHandler.handleRequest(SendErrorPageHandler.java:52)
at [email protected]//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at [email protected]//io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:269)
at [email protected]//io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:78)
at [email protected]//io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:133)
at [email protected]//io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:130)
at [email protected]//io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
at [email protected]//io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
at [email protected]//org.wildfly.extension.undertow.security.SecurityContextThreadSetupAction.lambda$create$0(SecurityContextThreadSetupAction.java:105)
at [email protected]//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1530)
at [email protected]//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1530)
at [email protected]//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1530)
at [email protected]//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1530)
at [email protected]//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1530)
at [email protected]//io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:249)
at [email protected]//io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:78)
at [email protected]//io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:99)
at [email protected]//io.undertow.server.Connectors.executeRootHandler(Connectors.java:387)
at [email protected]//io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:841)
at [email protected]//org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
at [email protected]//org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:1990)
at [email protected]//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1486)
at [email protected]//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1348)
at [email protected]//org.xnio.XnioWorker$WorkerThreadFactory$1$1.run(XnioWorker.java:1280)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: javax.transaction.NotSupportedException: WFTXN0001: A transaction is already in progress
at [email protected]//org.wildfly.transaction.client.ContextTransactionManager.begin(ContextTransactionManager.java:60)
at [email protected]//org.wildfly.transaction.client.LocalUserTransaction.begin(LocalUserTransaction.java:48)
at deployment.my-app.war//org.springframework.transaction.jta.JtaTransactionManager.doJtaBegin(JtaTransactionManager.java:886)
at deployment.my-app.war//org.springframework.transaction.jta.JtaTransactionManager.doBegin(JtaTransactionManager.java:849)
... 105 more
I’ve been searching for any hints at what the issue might be with no luck. I’m unclear if it’s a JBoss issues configuration issue or Sprint Boot configuration. I’d greatly appreciate any insight anyone might be able to provide.