在http://www.vermatech.com/code/SpringTransactionExamples.html给出的第一个案例研究中, 程序正在调用两种方法,即
testModel.deleteAllCountries();
testModel.initializeCountries();
其中initializeCountries抛出运行时异常。对于这两种方法,事务定义属性为PROPAGATION_REQUIRED。仍在deleteAllCountries下进行交易 方法得到提交但是在initializeCountries下的事务被回滚(根据同一案例研究中给出的日志)。
根据PROPAGATION_REQUIRED定义,它支持当前事务;如果不存在则创建一个新的。所以我的问题是initializeCountries方法下的事务 应该支持deleteAllCountries方法下的事务。我的意思是这两种方法都应该被视为单一交易。根据我的理解,还是应该提交或回滚完整的事务?不知道日志是如何分别对待它们的。
答案 0 :(得分:12)
“需要传播”定义为
支持当前事务,如果不存在则创建一个新事务。
在上面的例子中,deleteAllCountries方法在事务中执行并提交。调用initializeCountries时没有当前事务,因此它在第二个事务中执行,并且回滚它对第一个方法所做的更改没有影响。
传播适用于嵌套方法调用,而不适用于连续调用。如果你看the documentation:
当传播设置为PROPAGATION_REQUIRED时,为逻辑 为设置所在的每个方法创建事务范围 应用。每个这样的逻辑事务范围都可以确定 仅具有回滚状态,具有外部事务范围 在逻辑上独立于内部事务范围。的 当然,在标准的PROPAGATION_REQUIRED行为的情况下,所有这些 范围将映射到同一物理事务。那么一个 内部事务范围中设置的仅回滚标记确实会影响 外部交易实际提交的机会(正如您所期望的那样) 它来)。
但是,在内部事务范围设置的情况下 rollback-only标记,外部事务还没有决定 回滚本身,以及回滚(由内部静默触发) 事务范围)是意外的。相应的 此时抛出UnexpectedRollbackException。这是预料之中的 行为,以便永远不会误导交易的调用者 假设在确实没有执行提交时。所以,如果一个 内部事务(外部调用者不知道)默默地 将事务标记为仅回滚,外部调用者仍然调用 承诺。外部呼叫者需要接收 UnexpectedRollbackException清楚地表明回滚是 相反。
然后你可以看到所有这些都是关于内部和外部的,没有一个提到连续的呼叫。在您的情况下,对deleteAllCountries的调用是最外层的事务方法,因此当它成功完成时,Spring立即提交事务。然后你对initializeCountries的调用必须在一个单独的事务中执行,它是最外层的方法。
您的假设似乎是Spring会在第一个方法完成后保持事务处于打开状态,但这不是它的工作原理。为了获得您想要的效果,您可以在testModel上创建另一个方法,该方法包含对deleteAllCountries和initializeCountries的调用,使该方法具有事务性并为其提供属性PROPAGATION_REQUIRED。这样,第二种方法的回滚将导致第一种方法的更改也被回滚,因为包装方法将它们组合在一起。否则什么都没有告诉Spring这些东西应该是同一个交易的一部分。