Resin + Oracle + [Spring] + XA事务REQUIRES_NEW -内部事务提交失败



能否帮忙解决Resin + Oracle上XA事务的问题:

我们有WebApp,它必须执行业务事务,涉及Oracle 11.2.0.1和Ehcache 2.7。(实际上可能有各种组合-两个不同的Oracle数据源(不同的模式)带/不带Ehcache等)。这就是从普通JDBC使用切换到JTA事务划分的原因。

我们使用

:-使用Spring 3.2.1装饰的Resin JTA实现简化事务挂起,并使用编程方法定义事务边界("手动"使用TransactionManager进行挂起/恢复也会产生问题),如下:

public void doOuterTransaction() throws Throwable {
    DefaultTransactionDefinition def = new DefaultTransactionDefinition();
    def.setName("myTx");
    def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES);
    TransactionStatus status = txManager.getTransaction(def);
    Connection connection = null;
    Cache cache = null;
    try {
        cache = ...; // get cache from CacheManager
        connection = myDataSource.getConnection(); // or "DataSourceUtils.getConnection(myDataSource)" to guarantee same dbConnection from Spring
        // some business logic
        doInnerTransaction();
        // some business logic
        txManager.commit(status);
    } catch (Throwable ex) {
        txManager.rollback(status);
        throw ex;
    } finally {
        if (connection!=null) {
            connection.close();
        }
    }
}
public void doInnerTransaction() throws Throwable {
    DefaultTransactionDefinition def = new DefaultTransactionDefinition();
    def.setName("myTx");
    def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
    TransactionStatus status = txManager.getTransaction(def);
    Connection connection = null;
    Cache cache = null;
    try {
        cache = ...; // get cache from CacheManager
        connection = myDataSource.getConnection(); // or "DataSourceUtils.getConnection(myDataSource)" to guarantee same dbConnection from Spring
        // some business logic
        txManager.commit(status);
    } catch (Throwable ex) {
        txManager.rollback(status);
        throw ex;
    } finally {
        if (connection!=null) {
            connection.close();
        }
    }
}
  • 支持"XA"事务的Ehcache。
  • 树脂连接池与Oracle驱动程序" Oracle .jdbc.xa.client。OracleXADataSource",通过resin.conf配置如下

    <database>
    <name>my_xa_datasource</name>
    <jndi-name>jdbc/my_xa</jndi-name>
    <driver>
        <type>oracle.jdbc.xa.client.OracleXADataSource</type>
        <url>${MY_DB_URL}</url>
        <user>${MY_DB_USERNAME}</user>
        <password>${MY_DB_PASSWORD}</password>
    </driver>
    <max-connections>50</max-connections>
    <max-idle-time>60s</max-idle-time>
    <max-active-time>24h</max-active-time>
    <max-overflow-connections>15</max-overflow-connections>
    <ping>true</ping>
    <ping-table>DUAL</ping-table>
    <ping-interval>240s</ping-interval>
    <transaction-timeout>24h</transaction-timeout>
    <xa>true</xa>
    </database>
    

所有具有任何受影响资源组合且传播级别为REQUIRED的事务都可以正常工作。但是当我们遇到外部事务"REQUIRED"和内部事务"REQUIRES_NEW"的情况时,挂起外部事务会导致问题,内部事务无法提交。甚至,已经在运行的内部事务,我们可以看到来自外部事务的未提交的更改,这看起来完全错误。

行为取决于外部事务和内部事务涉及哪些资源。我们有以下案例:1. 在内部事务和外部事务中只使用Ehcache访问,即使内部事务使用REQUIRES_NEW也可以正常工作。

  1. 在外部事务中访问Ehcache,在内部事务中只访问DB,即使在内部事务中使用REQUIRES_NEW也可以正常工作。

  2. 在外部事务或两个事务中访问数据库的情况下(无论涉及多少数据源,即使数据源的使用不重叠事务边界),在提交内部事务时会产生以下错误:

_

ch.sc.common.ShortAGRuntimeException: org.springframework.transaction.TransactionSystemException:
JTA failure on commit; nested exception is com.caucho.transaction.SystemExceptionWrapper:
XA_RMERR: Resource manager error.
at ch.sc.glibs.mytest.MyTestServlet.doGet(MyTestServlet.java:34)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:120)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:97)
at com.caucho.server.dispatch.ServletFilterChain.doFilter(ServletFilterChain.java:109)
at ch.sc.common.http.filters.RegexpFilteringProxyFilter.doFilter(RegexpFilteringProxyFilter.java:65)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:89)
at ch.sc.common.http.filters.RegexpFilteringProxyFilter.doFilter(RegexpFilteringProxyFilter.java:65)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:89)
at ch.sc.common.http.filters.RegexpFilteringProxyFilter.doFilter(RegexpFilteringProxyFilter.java:65)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:89)
at ch.sc.common.http.filters.RegexpFilteringProxyFilter.doFilter(RegexpFilteringProxyFilter.java:65)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:89)
at ch.sc.common.http.filters.RegexpFilteringProxyFilter.doFilter(RegexpFilteringProxyFilter.java:65)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:89)
at ch.sc.common.http.filters.RegexpFilteringProxyFilter.doFilter(RegexpFilteringProxyFilter.java:65)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:89)
at ch.sc.common.http.filters.RegexpFilteringProxyFilter.doFilter(RegexpFilteringProxyFilter.java:65)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:89)
at ch.sc.common.http.filters.RegexpFilteringProxyFilter.doFilter(RegexpFilteringProxyFilter.java:65)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:89)
at com.caucho.server.security.SecurityFilterChain.doFilter(SecurityFilterChain.java:132)
at com.caucho.server.webapp.WebAppListenerFilterChain.doFilter(WebAppListenerFilterChain.java:114)
at com.caucho.server.webapp.WebAppFilterChain.doFilter(WebAppFilterChain.java:156)
at com.caucho.server.webapp.AccessLogFilterChain.doFilter(AccessLogFilterChain.java:95)
at com.caucho.server.dispatch.ServletInvocation.service(ServletInvocation.java:289)
at com.caucho.server.http.HttpRequest.handleRequest(HttpRequest.java:838)
at com.caucho.network.listen.TcpSocketLink.dispatchRequest(TcpSocketLink.java:1309)
at com.caucho.network.listen.TcpSocketLink.handleRequest(TcpSocketLink.java:1265)
at com.caucho.network.listen.TcpSocketLink.handleRequestsImpl(TcpSocketLink.java:1249)
at com.caucho.network.listen.TcpSocketLink.handleRequests(TcpSocketLink.java:1157)
at com.caucho.network.listen.TcpSocketLink.handleAcceptTaskImpl(TcpSocketLink.java:956)
at com.caucho.network.listen.ConnectionTask.runThread(ConnectionTask.java:117)
at com.caucho.network.listen.ConnectionTask.run(ConnectionTask.java:93)
at com.caucho.network.listen.SocketLinkThreadLauncher.handleTasks(SocketLinkThreadLauncher.java:169)
at com.caucho.network.listen.TcpSocketAcceptThread.run(TcpSocketAcceptThread.java:61)
at com.caucho.env.thread2.ResinThread2.runTasks(ResinThread2.java:173)
at com.caucho.env.thread2.ResinThread2.run(ResinThread2.java:118)
Caused by: org.springframework.transaction.TransactionSystemException:
JTA failure on commit; nested exception is com.caucho.transaction.SystemExceptionWrapper:
XA_RMERR: Resource manager error.
at org.springframework.transaction.jta.JtaTransactionManager.doCommit(JtaTransactionManager.java:1025)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
at ch.sc.glibs.mytest.MyTxTest.test3(MyTxTest.java:155)
at ch.sc.glibs.mytest.MyTxTest.doMainComplexTx(MyTxTest.java:81)
at ch.sc.glibs.mytest.MyTxTest.doTxTest(MyTxTest.java:50)
at ch.sc.glibs.mytest.MyTxTest__ResinScopeProxy.doTxTest(Unknown Source)
at ch.sc.glibs.mytest.MyTestServlet.doGet(MyTestServlet.java:32)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:120)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:97)
at com.caucho.server.dispatch.ServletFilterChain.doFilter(ServletFilterChain.java:109)
at ch.sc.common.http.filters.RegexpFilteringProxyFilter.doFilter(RegexpFilteringProxyFilter.java:65)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:89)
at ch.sc.common.http.filters.RegexpFilteringProxyFilter.doFilter(RegexpFilteringProxyFilter.java:65)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:89)
at ch.sc.common.http.filters.RegexpFilteringProxyFilter.doFilter(RegexpFilteringProxyFilter.java:65)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:89)
at ch.sc.common.http.filters.RegexpFilteringProxyFilter.doFilter(RegexpFilteringProxyFilter.java:65)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:89)
at ch.sc.common.http.filters.RegexpFilteringProxyFilter.doFilter(RegexpFilteringProxyFilter.java:65)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:89)
at ch.sc.common.http.filters.RegexpFilteringProxyFilter.doFilter(RegexpFilteringProxyFilter.java:65)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:89)
at ch.sc.common.http.filters.RegexpFilteringProxyFilter.doFilter(RegexpFilteringProxyFilter.java:65)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:89)
at ch.sc.common.http.filters.RegexpFilteringProxyFilter.doFilter(RegexpFilteringProxyFilter.java:65)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:89)
at com.caucho.server.security.SecurityFilterChain.doFilter(SecurityFilterChain.java:132)
at com.caucho.server.webapp.WebAppListenerFilterChain.doFilter(WebAppListenerFilterChain.java:114)
at com.caucho.server.webapp.WebAppFilterChain.doFilter(WebAppFilterChain.java:156)
at com.caucho.server.webapp.AccessLogFilterChain.doFilter(AccessLogFilterChain.java:95)
at com.caucho.server.dispatch.ServletInvocation.service(ServletInvocation.java:289)
at com.caucho.server.http.HttpRequest.handleRequest(HttpRequest.java:838)
at com.caucho.network.listen.TcpSocketLink.dispatchRequest(TcpSocketLink.java:1309)
at com.caucho.network.listen.TcpSocketLink.handleRequest(TcpSocketLink.java:1265)
at com.caucho.network.listen.TcpSocketLink.handleRequestsImpl(TcpSocketLink.java:1249)
at com.caucho.network.listen.TcpSocketLink.handleRequests(TcpSocketLink.java:1157)
at com.caucho.network.listen.TcpSocketLink.handleAcceptTaskImpl(TcpSocketLink.java:956)
at com.caucho.network.listen.ConnectionTask.runThread(ConnectionTask.java:117)
at com.caucho.network.listen.ConnectionTask.run(ConnectionTask.java:93)
at com.caucho.network.listen.SocketLinkThreadLauncher.handleTasks(SocketLinkThreadLauncher.java:169)
at com.caucho.network.listen.TcpSocketAcceptThread.run(TcpSocketAcceptThread.java:61)
at com.caucho.env.thread2.ResinThread2.runTasks(ResinThread2.java:173)
at com.caucho.env.thread2.ResinThread2.run(ResinThread2.java:118)
Caused by: com.caucho.transaction.SystemExceptionWrapper: XA_RMERR: Resource
manager error.
at com.caucho.transaction.TransactionImpl.heuristicException(TransactionImpl.java:1040)
at com.caucho.transaction.TransactionImpl.commitResources(TransactionImpl.java:931)
at com.caucho.transaction.TransactionImpl.commit(TransactionImpl.java:886)
at com.caucho.transaction.TransactionManagerImpl.commit(TransactionManagerImpl.java:324)
at com.caucho.transaction.UserTransactionImpl.commit(UserTransactionImpl.java:363)
at com.caucho.transaction.UserTransactionProxy.commit(UserTransactionProxy.java:171)
at org.springframework.transaction.jta.JtaTransactionManager.doCommit(JtaTransactionManager.java:1009)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
at ch.sc.glibs.mytest.MyTxTest.test3(MyTxTest.java:155)
at ch.sc.glibs.mytest.MyTxTest.doMainComplexTx(MyTxTest.java:81)
at ch.sc.glibs.mytest.MyTxTest.doTxTest(MyTxTest.java:50)
at ch.sc.glibs.mytest.MyTxTest__ResinScopeProxy.doTxTest(Unknown Source)
at ch.sc.glibs.mytest.MyTestServlet.doGet(MyTestServlet.java:32)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:120)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:97)
at com.caucho.server.dispatch.ServletFilterChain.doFilter(ServletFilterChain.java:109)
at ch.sc.common.http.filters.RegexpFilteringProxyFilter.doFilter(RegexpFilteringProxyFilter.java:65)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:89)
at ch.sc.common.http.filters.RegexpFilteringProxyFilter.doFilter(RegexpFilteringProxyFilter.java:65)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:89)
at ch.sc.common.http.filters.RegexpFilteringProxyFilter.doFilter(RegexpFilteringProxyFilter.java:65)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:89)
at ch.sc.common.http.filters.RegexpFilteringProxyFilter.doFilter(RegexpFilteringProxyFilter.java:65)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:89)
at ch.sc.common.http.filters.RegexpFilteringProxyFilter.doFilter(RegexpFilteringProxyFilter.java:65)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:89)
at ch.sc.common.http.filters.RegexpFilteringProxyFilter.doFilter(RegexpFilteringProxyFilter.java:65)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:89)
at ch.sc.common.http.filters.RegexpFilteringProxyFilter.doFilter(RegexpFilteringProxyFilter.java:65)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:89)
at ch.sc.common.http.filters.RegexpFilteringProxyFilter.doFilter(RegexpFilteringProxyFilter.java:65)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:89)
at com.caucho.server.security.SecurityFilterChain.doFilter(SecurityFilterChain.java:132)
at com.caucho.server.webapp.WebAppListenerFilterChain.doFilter(WebAppListenerFilterChain.java:114)
at com.caucho.server.webapp.WebAppFilterChain.doFilter(WebAppFilterChain.java:156)
at com.caucho.server.webapp.AccessLogFilterChain.doFilter(AccessLogFilterChain.java:95)
at com.caucho.server.dispatch.ServletInvocation.service(ServletInvocation.java:289)
at com.caucho.server.http.HttpRequest.handleRequest(HttpRequest.java:838)
at com.caucho.network.listen.TcpSocketLink.dispatchRequest(TcpSocketLink.java:1309)
at com.caucho.network.listen.TcpSocketLink.handleRequest(TcpSocketLink.java:1265)
at com.caucho.network.listen.TcpSocketLink.handleRequestsImpl(TcpSocketLink.java:1249)
at com.caucho.network.listen.TcpSocketLink.handleRequests(TcpSocketLink.java:1157)
at com.caucho.network.listen.TcpSocketLink.handleAcceptTaskImpl(TcpSocketLink.java:956)
at com.caucho.network.listen.ConnectionTask.runThread(ConnectionTask.java:117)
at com.caucho.network.listen.ConnectionTask.run(ConnectionTask.java:93)
at com.caucho.network.listen.SocketLinkThreadLauncher.handleTasks(SocketLinkThreadLauncher.java:169)
at com.caucho.network.listen.TcpSocketAcceptThread.run(TcpSocketAcceptThread.java:61)
at com.caucho.env.thread2.ResinThread2.runTasks(ResinThread2.java:173)
at com.caucho.env.thread2.ResinThread2.run(ResinThread2.java:118)
Caused by: oracle.jdbc.xa.OracleXAException
at oracle.jdbc.xa.OracleXAResource.checkError(OracleXAResource.java:1110)
at oracle.jdbc.xa.client.OracleXAResource.end(OracleXAResource.java:436)
at com.caucho.sql.DisjointXAResource.end(DisjointXAResource.java:105)
at com.caucho.env.dbpool.ManagedPoolItem.endResource(ManagedPoolItem.java:1017)
at com.caucho.env.dbpool.ManagedPoolItem.commit(ManagedPoolItem.java:957)
at com.caucho.transaction.TransactionImpl.commitResources(TransactionImpl.java:924)
at com.caucho.transaction.TransactionImpl.commit(TransactionImpl.java:886)
at com.caucho.transaction.TransactionManagerImpl.commit(TransactionManagerImpl.java:324)
at com.caucho.transaction.UserTransactionImpl.commit(UserTransactionImpl.java:363)
at com.caucho.transaction.UserTransactionProxy.commit(UserTransactionProxy.java:171)
at org.springframework.transaction.jta.JtaTransactionManager.doCommit(JtaTransactionManager.java:1009)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
at ch.sc.glibs.mytest.MyTxTest.test3(MyTxTest.java:155)
at ch.sc.glibs.mytest.MyTxTest.doMainComplexTx(MyTxTest.java:81)
at ch.sc.glibs.mytest.MyTxTest.doTxTest(MyTxTest.java:50)
at ch.sc.glibs.mytest.MyTxTest__ResinScopeProxy.doTxTest(Unknown Source)
at ch.sc.glibs.mytest.MyTestServlet.doGet(MyTestServlet.java:32)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:120)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:97)
at com.caucho.server.dispatch.ServletFilterChain.doFilter(ServletFilterChain.java:109)
at ch.sc.common.http.filters.RegexpFilteringProxyFilter.doFilter(RegexpFilteringProxyFilter.java:65)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:89)
at ch.sc.common.http.filters.RegexpFilteringProxyFilter.doFilter(RegexpFilteringProxyFilter.java:65)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:89)
at ch.sc.common.http.filters.RegexpFilteringProxyFilter.doFilter(RegexpFilteringProxyFilter.java:65)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:89)
at ch.sc.common.http.filters.RegexpFilteringProxyFilter.doFilter(RegexpFilteringProxyFilter.java:65)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:89)
at ch.sc.common.http.filters.RegexpFilteringProxyFilter.doFilter(RegexpFilteringProxyFilter.java:65)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:89)
at ch.sc.common.http.filters.RegexpFilteringProxyFilter.doFilter(RegexpFilteringProxyFilter.java:65)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:89)
at ch.sc.common.http.filters.RegexpFilteringProxyFilter.doFilter(RegexpFilteringProxyFilter.java:65)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:89)
at ch.sc.common.http.filters.RegexpFilteringProxyFilter.doFilter(RegexpFilteringProxyFilter.java:65)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:89)
at com.caucho.server.security.SecurityFilterChain.doFilter(SecurityFilterChain.java:132)
at com.caucho.server.webapp.WebAppListenerFilterChain.doFilter(WebAppListenerFilterChain.java:114)
at com.caucho.server.webapp.WebAppFilterChain.doFilter(WebAppFilterChain.java:156)
at com.caucho.server.webapp.AccessLogFilterChain.doFilter(AccessLogFilterChain.java:95)
at com.caucho.server.dispatch.ServletInvocation.service(ServletInvocation.java:289)
at com.caucho.server.http.HttpRequest.handleRequest(HttpRequest.java:838)
at com.caucho.network.listen.TcpSocketLink.dispatchRequest(TcpSocketLink.java:1309)
at com.caucho.network.listen.TcpSocketLink.handleRequest(TcpSocketLink.java:1265)
at com.caucho.network.listen.TcpSocketLink.handleRequestsImpl(TcpSocketLink.java:1249)
at com.caucho.network.listen.TcpSocketLink.handleRequests(TcpSocketLink.java:1157)
at com.caucho.network.listen.TcpSocketLink.handleAcceptTaskImpl(TcpSocketLink.java:956)
at com.caucho.network.listen.ConnectionTask.runThread(ConnectionTask.java:117)
at com.caucho.network.listen.ConnectionTask.run(ConnectionTask.java:93)
at com.caucho.network.listen.SocketLinkThreadLauncher.handleTasks(SocketLinkThreadLauncher.java:169)
at com.caucho.network.listen.TcpSocketAcceptThread.run(TcpSocketAcceptThread.java:61)
at com.caucho.env.thread2.ResinThread2.runTasks(ResinThread2.java:173)
at com.caucho.env.thread2.ResinThread2.run(ResinThread2.java:118)
在准备提交阶段(调用Oracle JAVA_XA),我们在内部看到ORA-25352 " no current transaction " " user session is not attached to any transaction "。Prepare返回一个错误代码)。在内部事务提交过程中,由于某些原因,应用程序涉及到外部事务中受影响的资源(数据源),这似乎是不正确的,因为在内部事务中没有使用db,我们预计不会调用Oracle。

最糟糕的是,使用Apache DBCP池代替树脂池实现解决了这个问题…使用Atomikos(包括TransactionManager实现和连接池实现)也工作得很好。但上述两种实现都有各自的问题。

此刻,我们假设我们有DB池或XA驱动程序配置的问题…这个问题是否可以与使用本地事务而不是全局事务等增强功能联系起来?我们尝试了各种资源定义(database, resource-ref),使用"xa-forbid-相同-rm",关闭spring事务同步,尝试使用TransactionManager手动挂起/恢复事务,等等-所有这些都没有运气。

欢迎任何想法/解决方案!

Resin/Spring/Oracle/XA事务组合工作完美。这里的关键是正确地使用DB连接。

所有DB连接必须在事务中打开。在本例中,此资源将隐式地为事务登记。我们的示例代码就是这样做的。

问题是我们在开始新事务时让数据库连接打开。这意味着在开始新事务之前,Resin的db池(又名UserConnection)提供的db连接没有返回到池中。由于某种原因,Resin TransactionManager实现隐式地将UNreturned db连接添加到内部事务中使用的资源列表中。内部事务提交失败,因为Oracle知道db连接已经在外部未提交的事务中使用。

可以安全地将db连接返回到池。在内部事务执行后(所有未提交的更改都不可见,因为树脂将在新事务中提供新的数据库连接),您可以在外部事务中再次请求数据库连接,该数据库连接将与启动内部事务之前的数据库连接完全相同,因此您将看到所有未提交的更改。因此,从resin的连接池将提供与当前UserTransaction相关的连接。

一个更重要的事情-如果你使用Spring从数据源(DataSourceUtils)获得连接,你必须在开始内部事务之前使用DataSourceUtils来释放连接,让Spring知道连接已经返回。实际上,Spring的另一个优点是,您可以拥有自己的额外TransactionSynchronization逻辑。您也可以直接使用数据源(不使用Spring),在这种情况下,您可以调用connection.close()将其返回到连接池。

最后,外部事务(任何事务)的代码应该如下:

public void doOuterTransaction() throws Throwable {
    DefaultTransactionDefinition def = new DefaultTransactionDefinition();
    def.setName("myTx");
    def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES);
    TransactionStatus status = txManager.getTransaction(def);
    Connection connection = null;
    Cache cache = null;
    try {
        try {
            cache = ...; // get cache from CacheManager
            connection = DataSourceUtils.getConnection(myDataSource);
            // some business logic
        } finally {
            DataSourceUtils.releaseConnection(connection, myDataSource);
        }
        doInnerTransaction();
        try {
            cache = ...; // get cache from CacheManager
            connection = DataSourceUtils.getConnection(myDataSource);
            // some other business logic 
        } finally {
            DataSourceUtils.releaseConnection(connection, myDataSource);
        }
    } catch (Throwable ex) {
        txManager.rollback(status);
        throw ex;
    }
    txManager.commit(status);
}

所以不要害怕获取和释放db连接。你有连接池-它很快。在连接上调用close()只会将其返回到池中(方法名"release"更好!)。激活UserTransaction将不会提交你的更改,直到你显式地调用commit()。

谢谢大家的帮助!

最新更新