1

您能否帮助解决 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。
  • Resin 连接池与 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. 即使对内部事务使用 REQUIRES_NEW,在外部事务中访问 Ehcache 并且仅在内部事务中访问 DB 也可以正常工作。

  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)

在内部,我们在准备提交阶段看到 ORA-25352“无当前事务”“用户会话未附加到任何事务”(调用 Oracle JAVA_XA.prepare 返回错误代码)。看起来好像在内部事务提交应用程序期间由于某种原因涉及外部事务中受影响的资源(数据源),这似乎是不正确的,因为在内部事务中没有使用数据库,我们预计不会调用 Oracle。

最糟糕的是,使用 Apache DBCP 池而不是 Resin 池实现解决了问题……使用 Atomikos(TransactionManager 实现和 Connections Pool 实现)也可以正常工作。但是两个提到的实现都有自己的问题。

目前我们假设我们在 DB 池或 XA 驱动程序配置方面存在问题……这个问题是否与使用本地事务而不是全局事务等任何增强相关联?我们尝试了各种资源定义(数据库,resource-ref),使用“xa-forbid-same-rm”,关闭 spring 事务同步,尝试手动使用 TransactionManager 来暂停/恢复事务等 - 一切都没有运气。

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

4

1 回答 1

1

Resin/Spring/Oracle/XA Transactions 组合完美运行。这里的关键是正确使用数据库连接。

所有数据库连接都必须在您的事务内打开。在这种情况下,该资源将被隐式地征入事务。我们的示例代码就是这样做的。

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

可以安全地将数据库连接返回到池中。执行内部事务后(因为树脂会在新事务中为您提供新的数据库连接,所以看不到所有未提交的更改)您可能会再次要求外部事务中的数据库连接,此数据库连接将与开始内部事务之前的完全相同,因此您将看到所有未提交的更改。因此,将从树脂的连接池中提供与当前 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);
}

所以不要害怕获取和释放数据库连接。你有连接池 - 它很快。在连接上调用 close() 只会将其返回到池中(方法名称“释放”要好得多!)。在您明确调用 commit() 之前,活跃的 UserTransaction 不会提交您的更改。

谢谢大家的帮助!

于 2013-04-19T16:03:22.917 回答