提问者:小点点

Spring是否真的开始了与REQUIRES_NEW的新事务?


我的Spring(4.1.1)应用程序部署在JBoss-6.10-最终实例上,因此它使用基于容器的事务管理器和数据源。对于消息传递,我使用TIBCOEMS8.1,并设置了XA队列连接工厂。Java版本是1.8。0_20。所有这些都在我的Ubuntu 14.04笔记本电脑上运行。

我需要通过JMS发送请求,然后等待回复。我调用的bean的事务传播设置为传播。需要,所以我需要在一个新的事务中发送请求,然后等待回复。这意味着请求是在一个单独的bean中发送的,事务传播设置为传播。REQUIRES_NEW。它有效,但是我从JBoss那里得到了一个令人担忧的警告:

14-10-02 12:06:12,902 WARN[org.jboss.tm.usertx.UserTransaction注册表](超文本传输协议-0.0.0.0-8080-1)错误通知监听器org.jboss.resource.connectionmanager.CachedConnectionManager@1917b4deuserTransactionStarted:java.lang.IllegalStateException:试图更改事务TransactionImple

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

查看堆栈跟踪后,我打开了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;
    }
}

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

从表面上看,它看起来像是正在使用现有事务而不是正在启动的新事务——看看“事务”是如何传递给doBegin(…)的。我也在doBegin中查看了,没有指示正在请求或创建新事务。这个视图似乎得到了堆栈跟踪和我从JBoss那里得到的警告的支持…


共1个答案

匿名用户

很高兴看到我不是一个人被困在这个没有韧带的洞里…

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

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

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

Spring端打开了一个缺陷,标记为“无法修复”,但它们提供了解决方法配置:

典型的解决方案是使用Spring的TransactionAware DataSourceProxy并在那里将“reobtainTransactionalConnections”标志切换为“true”

玩得开心!