Spring中的PROPAGATION_REQUIRED事务属性?

时间:2011-08-10 18:06:46

标签: java spring java-ee spring-transactions

http://www.vermatech.com/code/SpringTransactionExamples.html给出的第一个案例研究中, 程序正在调用两种方法,即

testModel.deleteAllCountries();
testModel.initializeCountries();

其中initializeCountries抛出运行时异常。对于这两种方法,事务定义属性为PROPAGATION_REQUIRED。仍在deleteAllCountries下进行交易 方法得到提交但是在initializeCountries下的事务被回滚(根据同一案例研究中给出的日志)。

根据PROPAGATION_REQUIRED定义,它支持当前事务;如果不存在则创建一个新的。所以我的问题是initializeCountries方法下的事务 应该支持deleteAllCountries方法下的事务。我的意思是这两种方法都应该被视为单一交易。根据我的理解,还是应该提交或回滚完整的事务?不知道日志是如何分别对待它们的。

1 个答案:

答案 0 :(得分:12)

“需要传播”定义为

  

支持当前事务,如果不存在则创建一个新事务。

在上面的例子中,deleteAllCountries方法在事务中执行并提交。调用initializeCountries时没有当前事务,因此它在第二个事务中执行,并且回滚它对第一个方法所做的更改没有影响。

传播适用于嵌套方法调用,而不适用于连续调用。如果你看the documentation

  

当传播设置为PROPAGATION_REQUIRED时,为逻辑   为设置所在的每个方法创建事务范围   应用。每个这样的逻辑事务范围都可以确定   仅具有回滚状态,具有外部事务范围   在逻辑上独立于内部事务范围。的   当然,在标准的PROPAGATION_REQUIRED行为的情况下,所有这些   范围将映射到同一物理事务。那么一个   内部事务范围中设置的仅回滚标记确实会影响   外部交易实际提交的机会(正如您所期望的那样)   它来)。

     

但是,在内部事务范围设置的情况下   rollback-only标记,外部事务还没有决定   回滚本身,以及回滚(由内部静默触发)   事务范围)是意外的。相应的   此时抛出UnexpectedRollbackException。这是预料之中的   行为,以便永远不会误导交易的调用者   假设在确实没有执行提交时。所以,如果一个   内部事务(外部调用者不知道)默默地   将事务标记为仅回滚,外部调用者仍然调用   承诺。外部呼叫者需要接收   UnexpectedRollbackException清楚地表明回滚是   相反。

然后你可以看到所有这些都是关于内部和外部的,没有一个提到连续的呼叫。在您的情况下,对deleteAllCountries的调用是最外层的事务方法,因此当它成功完成时,Spring立即提交事务。然后你对initializeCountries的调用必须在一个单独的事务中执行,它是最外层的方法。

您的假设似乎是Spring会在第一个方法完成后保持事务处于打开状态,但这不是它的工作原理。为了获得您想要的效果,您可以在testModel上创建另一个方法,该方法包含对deleteAllCountries和initializeCountries的调用,使该方法具有事务性并为其提供属性PROPAGATION_REQUIRED。这样,第二种方法的回滚将导致第一种方法的更改也被回滚,因为包装方法将它们组合在一起。否则什么都没有告诉Spring这些东西应该是同一个交易的一部分。