混合使用CMT和BMT的事务管理(BMT案例的数据过早提交)

时间:2013-09-30 17:49:01

标签: java spring hibernate transactions jta

我正在研究遗留应用程序。我们正在将它从JDBC转移到带有声明式事务的Spring 3.2 + Hibernate 4.1.12 + JTA 2。我看到容器管理事务(CMT)正如人们所期望的那样进行交易和回滚。我们使用Infinispan作为二级缓存(2LC)。有一个皱纹...

有一部分代码具有不同的入口点,该入口点在不同的线程中运行并使用程序化事务或Bean管理事务(BMT)。在BMT路径中,我看到在使用CMT的底层服务层中,事务正在加入BMT,正如人们所希望的那样。

两个入口点的持久性单元,数据源等相同。在这两种情况下,Hibernate autoflush代码都知道有一个事务并刷新到数据库驱动程序。在CMT入口点,数据库驱动程序保存数据,直到被告知提交或回滚。在BMT路径中,数据在刷新时被推送到数据库中 - 后来的提交或回滚没有效果或明显的意义。事务管理器是JtaTransactionManager。 JtaTransactionManager在@Configuration类中使用@EnableTransactionManagement定义,以启用CMT而不是<tx:annotation-driven/>元素。

单例JtaTransactionManager bean通过jtaPropertyManager.getJTAEnvironmentBean().getTransactionManager()jtaPropertyManager.getJTAEnvironmentBean().getUserTransaction()与ajuna UserTransaction和TransactionManager连接。 UserTransaction和TransactionManager都是原型@Bean定义。

我可以通过另一个查询工具的查询来确认数据是否存在于数据库中,以验证调试时的行为。

当我进行单元测试时,数据会按照BMT和CMT入口点的预期提交并回滚。

BMT由一个以不同方法开头和结尾的类来管理。它还具有执行实际工作单元的方法。 BMT的事务是使用PlatformTransactionManager而不是TransactionTemplate启动的。该类由另一个具有管理逻辑流逻辑的类驱动。我知道交易是按预期开始和结束的。在阅读各种其他讨论时,似乎暗示事务控制应该在单个方法中。我同意这是首选,但它是否必不可少?

如果Spring中的CMT管理的servlet生成一个新的Thread并使用一个计划thread.start()启动该线程,那么期望该新Thread中的BMT能够如上所述管理其事务是否合理?

JNDI检索数据源。使用XA或非XA不会影响结果。

我无法发布代码。

As a reference, here is the link to the Spring 3.1 docs on transaction in chapter 11.

已添加2013/10/04 - 我看到Spring使用JtaTransactionManagerBeanDefinitionParser根据感知的容器构建所需的JtaTransactionManager。使用它时,JTA事务管理器将在afterPropertiesSet UserTransaction,TransactionManager和TransactionSynchronizationRegistry中自行设置。

看来我确实仍然在CMT中泄漏数据,但是如果没有调试器或者由于事务通常提交而不自然地强制错误,很难察觉/观察到这一点。

看来我的问题是我已经部分绕过了JCA,以至于JCA正在使用不同的TransactionManager。

部分答案 - 因为我已经在CMT和BMT的混合中正确地看到了这个交易,我知道可以在一个方法中启动BMT事务并在另一个方法中提交。

问题仍然存在:如果Spring中的CMT托管的servlet生成一个新的Thread并使用一个计划thread.start()启动该线程,那么期望新的BMT是否合理是否合理如上所述,线程能够管理其交易吗?

1 个答案:

答案 0 :(得分:1)

从JTA 1.1规范(http://download.oracle.com/otn-pub/jcp/jta-1.1-spec-oth-JSpec/jta-1_1-spec.pdf)3.1节,很明显该事务绑定到该线程。这由TransactionManager管理。如果线程是创建事务的线程,那么应该能够期望线程能够在事务上下文中执行操作。

请注意,嵌套事务的支持是可选的,如JTA规范的相同部分所述。

我遇到的实际问题是托管数据源使用的是事务管理器的不同实例,而不是应用程序中的bean。更改应用程序代码以对容器提供的TransactionManager执行JNDI查找,允许托管数据源参与与应用程序相同的事务。