Spring是否真的使用REQUIRES_NEW开始新交易?

Joh*_*han 5 java jboss spring-transactions spring-jms

我的spring(4.1.1)应用程序部署在JBoss-6.10-final实例上,因此它使用基于容器的事务管理器和数据源。对于消息传递,我将TIBCO EMS 8.1与XA队列连接工厂一起使用。Java版本是1.8.0_20。所有这些都在我的Ubuntu 14.04笔记本电脑上运行。

我需要通过JMS发送请求,然后等待回复。我从中调用的Bean的事务传播设置为Propagation.REQUIRED,因此我需要在新事务中发送请求,然后等待答复。这意味着请求是在单独的Bean中发送的,事务传播设置为Propagation.REQUIRES_NEW。它可行,但是我收到来自JBoss的令人担忧的警告:

14-10-02 12:06:12,902警告[org.jboss.tm.usertx.UserTransactionRegistry](http-0.0.0.0-8080-1)将userTransactionStarted通知侦听器org.jboss.resource.connectionmanager.CachedConnectionManager@1917b4de时出错: java.lang.IllegalStateException:尝试更改事务TransactionImple <ac,BasicAction:0:ffff7f000101:126a:542d2010:d8状态:ActionStatus.RUNNING>登记!在org.jboss.resource.connectionmanager.TxConnectionManager $ TxConnectionEventListener.enlist(TxConnectionManager.java:690)在org.jboss.resource.connectionmanager.TxConnectionManager.transactionStarted(TxConnectionManager.java:427)在org.jboss.resource.connectionmanager.CachedConnection org.jboss.tm.usertx.client.ServerVMClientUserTransaction.begin(ServerVMClientUserTransaction.begin(ServerVMClientUserTransaction.java:141)处的org.jboss.tm.usertx.UserTransactionRegistry.userTransactionStarted(UserTransactionRegistry.java:119)处的.userTransactionStarted(CachedConnectionManager.java:350) org.springframework.transaction.support的org.springframework.transaction.jta.JtaTransactionManager.doJtaBegin(JtaTransactionManager.java:875)在org.springframework.transaction.jta.JtaTransactionManager.doBegin(JtaTransactionManager.java:832)在org.springframework.transaction.support。org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(transaction438)上的AbstractPlatformTransactionManager.handleExistingTransaction(AbstractPlatformTransactionManager.java:425)在org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:349)在org.springframework.transaction.interceptor.TransactionAspectSupport。 org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)的org.springframework.aop.framework.ReflectiveMethodInvocation.proceed的.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:261) .java:179),位于com.sun的org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)。com.izazi.ioriginate.framework.spring.jms.AbstractRequestReply.request(AbstractRequestReply.java:58)上的proxy。$ Proxy234.request(未知源)com.izazi.ioriginate.service.addressvalidation.AddressValidationServiceImpl.validate(AddressValidationServiceImpl。 java:34)位于sun.reflect.NativeMethodAccessorImpl.invoke0(本地方法)位于sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)位于sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)上的.reflect.Method.invoke(Method.java:483),org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190 ),网址为org.springframework.aop.framework.ReflectiveMethodInvocation。在org.org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:266)处在org.springframework.transaction.interaction.interceptor.TransactionInterceptor $ 1.proceedWithInvocation(TransactionInterceptor.java:98)处进行(ReflectiveMethodInvocation.java:157)。在org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)的springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)在org.springframework.aop.framework.JdkDynamicAopProxy.invoke(Jdk com.sun.proxy。$ Proxy235.validate(java:207)com.izazi.ioriginate.services.dwr.AddressValidation.validate(AddressValidation.java:40)处sun.reflect.NativeMethodAccessorImpl.invoke0(Native)方法)在太阳下。org.directwebremoting.impl上的java.lang.reflect.Method.invoke(Method.java:483)上的sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)上的reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) org.directwebremoting.impl.DefaultRemoter的.ExecuteAjaxFilter.doFilter(ExecuteAjaxFilter.java:34)org.directwebremoting.impl.DefaultRemoter.execute(DefaultRemoter.java:431)的org.directwebremoting.impl.DefaultRemoter $ 1.doFilter(DefaultRemoter.java:428) org.org.directwebremoting.servlet.PlainCallHandler.handle(PlainCallHandler.java:52)处的org.directwebremoting.servlet.UrlProcessor.handle(UrlProcessor.java:101)处的.impl.DefaultRemoter.execute(DefaultRemoter.java:283) javax.servlet.http.HttpServlet.service(HttpServlet.java:上的directwebremoting.servlet.DwrServlet.doPost(DwrServlet.java:146)754)在org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:324)在javax.servlet.http.HttpServlet.service(HttpServlet.java:847)在org.apache.catalina.core.ApplicationFilterChain.doFilter (ApplicationFilterChain.java:242)在org.springframework.security.web.FilterChainProxy $ VirtualFilterChain.doFilter(FilterChainProxy.java:330)在org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118) )的org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84)的org.springframework.security.web.FilterChainProxy $ VirtualFilterChain.doFilter(FilterChainProxy.java:342)的org.springframework。 security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter。org.springframework.security.web.FilterChainProxy $ VirtualFilterChain.doFilter(FilterChainProxy.java:342)上org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)上的java:113) org.springframework.security.web.FilterChainProxy $ VirtualFilterChain.doFilter(FilterChainProxy.java:342)位于org.springframework.security.web.FilterChainProxy $ VirtualFilterChain org.springframework.security.web.Filterapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:154)上的.doFilter(FilterChainProxy.java:342)org.springframework.security.web.FilterChainProxy $ VirtualFilterChain.doFilter(FilterChainProxy.java:342)在org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)在org.springframework.security.web.FilterChainProxy $ VirtualFilterChain.doFilter(FilterChainProxy.java:342)在org.springframework.security org.springframework.security.web.FilterChainProxy $ VirtualFilterChain.doFilter(FilterChainProxy.java:342)上的.web.authentication.www.BasicAuthenticationFilter.doFilter(BasicAuthenticationFilter.java:201)在org.springframework.security.web.authentication.ui org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter处的.DefaultLoginPageGeneratingFilter.doFilter(DefaultLoginPageGeneratingFilter.java:155)位于org.springframework.security.web.FilterChainProxy $ VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.FilterChainProxy $ VirtualFilterChain.doFilter(FilterChainProxy.java:342)上的doFilter(AbstractAuthenticationProcessingFilter.java:199)org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java: 110)在org.springframework.security.web.FilterChainProxy $ VirtualFilterChain.doFilter(FilterChainProxy.java:342)在org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50) org.springframework.security.web.FilterChainProxy $ VirtualFilterChain.doFilter(FilterChainProxy.java:342)上的.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)在org.springframework.security.web.context.SecurityContextPersistenceFilter 。org.org.springframework.security.web.FilterChainProxy $ VirtualFilterChain.doFilter(FilterChainProxy.java:342)处的org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)处的doFilter(SecurityContextPersistenceFilter.java:87) org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344)的org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy)的.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160) .java:261)位于org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:274)位于org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:242)位于org.apache.catalina core.StandardWrapperValve.invoke(StandardWrapperValve.java:275)在org.jboss.modcluster.catalina的org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:181)的org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161) org.jboss.modcluster.catalina.CatalinaContext $ RequestListenerValve.invoke(CatalinaContext.java:261)上的.CatalinaContext $ RequestListenerValve.event(CatalinaContext.java:285)在org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve .java:88),位于org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:159),位于org.jboss.web.tomcat.security.SecurityContextSecurity.SecurityContext EstablishmentmentValve.invoke(SecurityContext EstablishmentmentValve.java:100)。位于org.jboss.web.tomcat.service.jca.CachedConnectionValve的catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)。在org.jboss的org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)的org.apache.catalina.valves.RequestDumperValve.invoke(RequestDumperValve.java:151)的invoke(CachedConnectionValve.java:158) .web.tomcat.service.request.ActiveRequestResponseCacheValve.invoke(ActiveRequestResponseCacheValve.java:53)位于org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:362)位于org.apache.coyote.http11.Http11Processor.process (Http11Processor.java:877)在org.apache.coyote.http11.Http11Protocol $ Http11ConnectionHandler.process(Http11Protocol.java:654)在org.apache.tomcat.util.net.JIoEndpoint $ Worker.run(JIoEndpoint.java:951) )在java.lang.Thread.run(Thread.java:745)151)在org.jboss.web.tomcat.service.request.ActiveRequestResponseCacheValve.invoke(ActiveRequestResponseCacheValve.java:53)在org.jboss.web.tomcat.service.request(ActiveRequestResponseCacheValve.java:53)在org.apache.catalina.core.StandardEngineValve.java:109 org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877)上的.connector.CoyoteAdapter.service(CoyoteAdapter.java:362)在org.apache.coyote.http11.Http11Protocol $ Http11ConnectionHandler.process(Http11Protocol.java) :654),位于org.apache.tomcat.util.net.JIoEndpoint $ Worker.run(JIoEndpoint.java:951),位于java.lang.Thread.run(Thread.java:745)151)在org.jboss.web.tomcat.service.request.ActiveRequestResponseCacheValve.invoke(ActiveRequestResponseCacheValve.java:53)在org.jboss.web.tomcat.service.request(ActiveRequestResponseCacheValve.java:53)在org.apache.catalina.core.StandardEngineValve.java:109 org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877)上的.connector.CoyoteAdapter.service(CoyoteAdapter.java:362)在org.apache.coyote.http11.Http11Protocol $ Http11ConnectionHandler.process(Http11Protocol.java) :654),位于org.apache.tomcat.util.net.JIoEndpoint $ Worker.run(JIoEndpoint.java:951),位于java.lang.Thread.run(Thread.java:745)org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877)的CoyoteAdapter.service(CoyoteAdapter.java:362)org.apache.coyote.http11.Http11Protocol $ Http11ConnectionHandler.process(Http11Protocol.java:654)的CoyoteAdapter.service(CoyoteAdapter.java:362)在org.apache.tomcat.util.net.JIoEndpoint $ Worker.run(JIoEndpoint.java:951)在java.lang.Thread.run(Thread.java:745)org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877)的CoyoteAdapter.service(CoyoteAdapter.java:362)org.apache.coyote.http11.Http11Protocol $ Http11ConnectionHandler.process(Http11Protocol.java:654)的CoyoteAdapter.service(CoyoteAdapter.java:362)在org.apache.tomcat.util.net.JIoEndpoint $ Worker.run(JIoEndpoint.java:951)在java.lang.Thread.run(Thread.java:745)

...在EMS方面,我看到了一些XA错误:

johan @ my_machine:〜/ opt / jboss-6.1.0.Final / bin $ 2014-10-02 10:43:15.801错误:不存在的使用者的交易记录:15 connID = 16 sessID = 20 {formatID = 131076 gtrid_length = 29 bqual_length = 28 data =%00%00%00%00%00%00%00%00%00%00%00%FF%FF%7F%00%01%01%00%00%12jT-%0D *%00 %00%00%AF1%00%00%00%00%00%00%00%00%00%00%00%FF%FF%7F%00%01%01%01%00%00%12jT-%0D *%00 %00%00%B1} 2014-10-02 10:43:15.832错误:处理xa结束时出错-事务标记为ROLLBACKONLY,异常。connID = 16 sessID = 20 {formatID = 131076 gtrid_length = 29 bqual_length = 28 data =%00%00%00%00%00%00%00%00%00%00%00%FF%FF%7F%00%01%01 %00%00%12jT-%0D *%00%00%00%AF1%00%00%00%00%00%00%00%00%00%00%00%FF%FF%7F%00%01%01 %00%00%12jT-%0D *%00%00%00%B1}

在查看了堆栈跟踪之后,我打开了Spring的AbstractPlatformTransactionManager的源代码,并遇到了以下用于REQUIRES_NEW处理的代码(从415行开始):

if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
    if (debugEnabled) {
        logger.debug("Suspending current transaction, creating new transaction with name [" +
                definition.getName() + "]");
    }
    SuspendedResourcesHolder suspendedResources = suspend(transaction);
    try {
        boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
        DefaultTransactionStatus status = newTransactionStatus(
                definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
        doBegin(transaction, definition);
        prepareSynchronization(status, definition);
        return status;
    }
    catch (RuntimeException beginEx) {
        resumeAfterBeginException(transaction, suspendedResources, beginEx);
        throw beginEx;
    }
    catch (Error beginErr) {
        resumeAfterBeginException(transaction, suspendedResources, beginErr);
        throw beginErr;
    }
}
Run Code Online (Sandbox Code Playgroud)

我的问题是:新交易从哪里开始?

从表面上看,似乎正在使用现有事务,而不是开始新事务-查看如何将“事务”传递给doBegin(...)。我也查看了doBegin,没有迹象表明正在请求或创建新事务。堆栈跟踪和我从JBoss获得的警告似乎支持该视图。

Gab*_*ica 4

很高兴看到我并不孤单地被困在这个黑暗的洞里......

据我所知,这里描述了此警告的深层原因(线程结束)

当外部事务挂起并启动新的内部事务时,Jboss 连接池为内部事务检索的托管连接与外部事务的托管连接相同,这导致抛出 IllegalStateException!

这是由于 jboss JCA 合约实现的特定行为 ( Lazy JCA enlistment)。

弹簧端已打开缺陷,标记为“无法修复”,但他们提供了解决方法配置:

典型的解决方案是使用 Spring 的 TransactionAwareDataSourceProxy 并将“reobtainTransactionalConnections”标志切换为“true”

玩得开心 !