3

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

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

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

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

4

1 回答 1

13

“需要传播”定义为

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

在上述情况下,deleteAllCountries 方法在事务中执行并提交。调用 initializeCountries 时没有当前事务,所以它在第二个事务中执行,回滚对第一个方法所做的更改没有影响。

传播适用于嵌套的方法调用,而不是连续的方法调用。如果您查看文档

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

但是,在内部事务范围设置了仅回滚标记的情况下,外部事务尚未决定回滚本身,因此回滚(由内部事务范围静默触发)是意外的。此时会引发相应的 UnexpectedRollbackException。这是预期的行为,因此事务的调用者永远不会被误导以为执行了提交,而实际上并没有执行。因此,如果内部事务(外部调用者不知道)默默地将事务标记为仅回滚,外部调用者仍会调用提交。外部调用者需要接收 UnexpectedRollbackException 以清楚地指示执行了回滚。

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

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

于 2011-08-10T18:11:50.450 回答