Transaction Propagation
本节介绍了 Spring 中事务传播的一些语义。请注意,本节并不是对事务传播的正确介绍。相反,它详细介绍了 Spring 中关于事务传播的一些语义。
在 Spring 管理的事务中,要注意物理和逻辑事务之间的区别,以及传播设置如何适用于这种区别。
了解 PROPAGATION_REQUIRED
PROPAGATION_REQUIRED 强制执行一个物理事务,如果还没有事务存在,就在当前作用域中执行,或者参与为更大作用域定义的现有 「外部」事务。在 同一线程 内的常见调用堆栈安排中,这是一个很好的缺省(例如,一个委托给几个存储库方法的服务面,其中所有的底层资源都必须参与到服务级事务中)。
:::info 默认情况下,参与的事务会加入外层作用域的特性,默默地忽略本地隔离级别、超时值或只读标志(如果有的话)。如果你想在参与具有不同隔离级别的现有事务时拒绝隔离级别声明,可以考虑在你的事务管理器上把 validateExistingTransactions 标志切换为 true。这种非宽松模式也拒绝只读错配(也就是说,一个内部的读写事务试图参与一个只读的外部范围)。 :::
当传播设置为 PROPAGATION_REQUIRED 时,为应用该设置的每个方法创建一个逻辑事务范围。每个这样的逻辑事务作用域都可以单独确定回滚状态,外部事务作用域在逻辑上独立于内部事务作用域。在标准的 PROPAGATION_REQUIRED 行为中,所有这些作用域被映射到同一个物理事务。所以在内部事务作用域中设置的回滚标记确实会影响外部事务实际提交的机会。
然而,在内层事务作用域设置仅回滚标记的情况下,外层事务还没有决定回滚本身,所以回滚(由内层事务作用域默默地触发)是意外的。这时会抛出一个相应的 UnexpectedRollbackException。这是预期的行为,这样事务的调用者就不会被误导,以为已经执行了提交,而实际上并没有。因此,如果一个内部事务(外部调用者并不知道)默默地将一个事务标记为只回滚,外部调用者仍然会调用提交。外方调用者需要收到一个 UnexpectedRollbackException,以清楚地表明执行的是回滚。(简单说,内部事务设置了回滚,外部事务继续提交事物的话,就会收到一个异常)
了解 PROPAGATION_REQUIRES_NEW
PROPAGATION_REQUIRES_NEW 与 PROPAGATION_REQUIRED 相反,它总是为每个受影响的事务范围使用一个独立的物理事务,从不参与一个外部范围的现有事务。在这样的安排中,底层资源事务是不同的,因此,可以独立地提交或回滚,外部事务不受内部事务回滚状态的影响,内部事务的锁在其完成后立即释放。这样一个独立的内部事务也可以声明自己的隔离级别、超时和只读设置,并且不继承外部事务的特性。.
了解 PROPAGATION_NESTED
PROPAGATION_NESTED 使用一个具有多个保存点的单一物理事务,它可以回滚到这些保存点。这种部分回滚让内部事务范围触发其范围的回滚,外部事务能够继续物理事务,尽管一些操作已经被回滚。这种设置通常被映射到 JDBC 保存点上,所以它只适用于 JDBC 资源事务。参见Spring 的 DataSourceTransactionManager。