TransactionAttribute注释

TransactionAttribute注释

本文介绍了TransactionAttribute注释(@REQUIRES_NEW)被忽略的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了两个单独事务的问题,这些事务以与实际执行它们相反的顺序刷新到数据库。

I have a problem with two separate transactions that are flushed to the database in a reverse order to that in which they're actually executed.

这是业务案例:有一个RemoteJob-RemoteJobEvent一对多关系。每次创建新事件时,都会获取时间戳并在RemoteJob和RemoteJobEvent的lastModified字段中设置,并且持久保存两个记录(一次更新+一次插入)。

Here's the business case: there's a RemoteJob-RemoteJobEvent one-to-many relation. Every time a new event is created, a timestamp is obtained and set in the lastModified field of both RemoteJob and RemoteJobEvent, and two records are persisted (one update + one insert).

这是代码中的样子:

 c> addEventIfNotThere()完成了!更重要的是,它以错误的顺序执行,并且版本列值清楚地表明第二个事务没有前一个事务的结果信息,即使第一个应该已经提交(注意日志顺序,lastModified字段值)和事件代码):

Here's the trouble: OpenJPA seems to flush both event-adding transactions no sooner than after the addEventIfNotThere() completes! What's more, it does it in a wrong order, and version column values clearly show that the second transaction has no information of the results of the preceding one, even though the first one should have been committed (note the log order, lastModified field values and event codes):

2011-07-08T10:45:51.386 [WorkManager.DefaultWorkManager : 7] TRACE [openjpa.jdbc.SQL] - <t 2080472065, conn 1753966731> executing prepstmnt 1859546838 INSERT INTO RemoteJobEvent (id, eventCode, lastModified, version, remotejobid) VALUES (?, ?, ?, ?, ?) [params=(long) 252, (short) 11, (Timestamp) 2011-07-08 10:45:51.381, (int) 1, (long) 111]
2011-07-08T10:45:51.390 [WorkManager.DefaultWorkManager : 7] TRACE [openjpa.jdbc.SQL] - <t 2080472065, conn 1753966731> executing prepstmnt 60425114 UPDATE RemoteJob SET lastModified = ?, version = ? WHERE id = ? AND version = ? [params=(Timestamp) 2011-07-08 10:45:51.381, (int) 3, (long) 111, (int) 2]
2011-07-08T10:45:51.401 [WorkManager.DefaultWorkManager : 7] TRACE [openjpa.jdbc.SQL] - <t 2080472065, conn 815411354> executing prepstmnt 923940626 INSERT INTO RemoteJobEvent (id, eventCode, lastModified, version, remotejobid) VALUES (?, ?, ?, ?, ?) [params=(long) 253, (short) 10, (Timestamp) 2011-07-08 10:45:51.35, (int) 1, (long) 111]
2011-07-08T10:45:51.403 [WorkManager.DefaultWorkManager : 7] TRACE [openjpa.jdbc.SQL] - <t 2080472065, conn 815411354> executing prepstmnt 1215645813 UPDATE RemoteJob SET lastModified = ?, version = ? WHERE id = ? AND version = ? [params=(Timestamp) 2011-07-08 10:45:51.35, (int) 3, (long) 111, (int) 2]

当然,这会产生 OptimisticLockException - 它在两个环境中的行为方式相同:使用Apache Derby / Tomcat /进行测试Atomikos Transaction Essentials,以及WebSphere 7.0 / Oracle 11的目标。

This, of course, produces an OptimisticLockException -- it acts the same way in two environments: test with Apache Derby/Tomcat/Atomikos Transaction Essentials, and target with WebSphere 7.0/Oracle 11.

我的问题是:这怎么可能,交易边界不受尊重?我了解JPA提供商可以在一次交易中自由选择 中的SQL订单,但它不能重新订购整个交易,可以吗?

My question is: how is this possible, that transaction borders are not respected? I understand that a JPA provider is free to choose SQL ordering within one transaction, but it cannot reorder whole transactions, can it?

有关我们环境的更多信息:提供的代码是Spring 3.0.5 JMS消息处理程序(DefaultMessageListenerContainer)的一部分; Spring也用于bean注入,但基于注释的事务管理使用系统事务管理器(Websphere的/ Atomikos,如上所述),这就是使用EJB3而不使用Spring事务注释的原因。

Some more info about our environment: the presented code is a part of a Spring 3.0.5 JMS message handler (DefaultMessageListenerContainer); Spring is also used for bean injections, but the annotation-based transaction management uses the system transaction manager (Websphere's/Atomikos, as above), that's why EJB3 and not Spring transactional annotations are used.

我希望这引起一些兴趣,在这种情况下,如果需要,我很乐意提供更多信息。

I hope this raises some interest, in which case I'll gladly supply more info, if needed.

推荐答案

我没有读过Spring代理如何工作的受害者,负责基于注释的交易支持。

I fell victim to not having read up on how Spring proxies work, the ones responsible for annotation-based transaction support.

结果是 addEvent 在同一个类中调用方法时,将忽略REQUIRES_NEW注释。在这种情况下Spring事务代理不起作用,因此代码运行在当前的交易—这是完全错误的,因为它在调用 helper.addEventIfNotThere()完成后结束(长)。另一方面,后一种方法从另一个类调用,因此REQUIRES_NEW真正启动并作为单独的事务提交。

It turns out the addEvent's REQUIRES_NEW annotation is ignored when the method is called from within the same class. The Spring transactional proxy does not come to work in this case, so the code runs in the current transaction — which is totally wrong, as it ends (long) after the call to helper.addEventIfNotThere() completes. The latter method, on the other hand, is called from another class, so the REQUIRES_NEW really starts and commits as a separate transaction.

I将 addEvent()方法移动到一个单独的类中,问题就消失了。另一种解决方案可能是改变< tx:annotation-driven /> 配置的工作方式;更多信息:。

I moved the addEvent() method to a separate class and the problem disappeared. Another solution could be changing the way the <tx:annotation-driven/> configuration works; more info here: Spring Transaction Management reference.

这篇关于TransactionAttribute注释(@REQUIRES_NEW)被忽略的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-04 07:10
查看更多