对于最新的稳定版本,请使用 Spring Framework 7.0.6!spring-doc.cadn.net.cn

事务传播

本节描述了Spring中事务传播的一些语义。请注意,本节并不是对事务传播的完整介绍。而是详细说明了关于Spring中事务传播的一些语义。spring-doc.cadn.net.cn

在Spring管理的事务中,要注意物理事务和逻辑事务之间的区别,以及传播设置如何应用于这种区别。spring-doc.cadn.net.cn

了解 PROPAGATION_REQUIRED

tx prop required

PROPAGATION_REQUIRED 强制进行物理事务,如果当前作用域中尚不存在事务,则在当前作用域内进行,或者参与已定义的“外部”事务(适用于更大作用域)。这在同一个线程内的常见调用堆栈结构中是一个很好的默认选项(例如,一个服务外观,它将多个存储库方法进行委派,其中所有底层资源都必须参与服务级事务)。spring-doc.cadn.net.cn

默认情况下,参与事务会继承外部作用域的特性, 忽略本地隔离级别、超时值或只读标志(如果有)。 如果您希望在参与现有事务时拒绝不同的隔离级别声明,请考虑将事务管理器上的 validateExistingTransactions 标志切换为 true。这种非宽松模式还会拒绝只读不匹配的情况(即,一个内部的读写事务尝试参与只读的外部作用域)。

当传播设置为 PROPAGATION_REQUIRED 时,会在应用该设置的每个方法上创建一个逻辑事务范围。每个这样的逻辑事务范围可以单独确定回滚只读状态,外部事务范围与内部事务范围在逻辑上是独立的。在标准 PROPAGATION_REQUIRED 行为的情况下,所有这些范围都会映射到同一个物理事务。因此,在内部事务范围内设置的回滚只读标记会影响外部事务实际提交的机会。spring-doc.cadn.net.cn

然而,在内部事务作用域设置回滚标记的情况下,外部事务尚未自行决定是否回滚,因此由内部事务作用域静默触发的回滚是不可预期的。此时会抛出相应的UnexpectedRollbackException。这是预期的行为,以便事务调用者永远不会被误导,认为实际并未执行提交操作时却以为已经提交。因此,如果内部事务(外部调用者并不知情)静默地将事务标记为回滚-only,外部调用者仍然会调用commit。外部调用者需要收到一个UnexpectedRollbackException,以明确表示执行了回滚操作。spring-doc.cadn.net.cn

了解 PROPAGATION_REQUIRES_NEW

tx prop requires new

PROPAGATION_REQUIRES_NEW,与 PROPAGATION_REQUIRED 相比,为每个受影响的事务范围始终使用独立的物理事务,从不参与外部范围的现有事务。在这种安排中,底层资源事务是不同的,因此可以独立提交或回滚,外部事务不会受到内部事务回滚状态的影响,且内部事务在完成之后会立即释放其锁。这种独立的内部事务还可以声明自己的隔离级别、超时时间和只读设置,而不会继承外部事务的特性。spring-doc.cadn.net.cn

与外部事务关联的资源将在外部事务中保持绑定,而内部事务将获取自己的资源,例如新的数据库连接。这可能导致连接池耗尽,并且如果多个线程具有活动的外部事务并等待获取用于其内部事务的新连接,而连接池不能再提供任何此类内部连接,可能会导致死锁。除非您的连接池已适当配置,其大小至少超过并发线程数1个,否则不要使用PROPAGATION_REQUIRES_NEW

了解 PROPAGATION_NESTED

PROPAGATION_NESTED 使用一个带有多个保存点的物理事务,它能够回滚到这些保存点。这种部分回滚使得内部事务范围可以为其范围触发回滚,而外部事务可以在某些操作已被回滚的情况下继续进行物理事务。此设置通常映射到 JDBC 保存点,因此仅适用于 JDBC 资源事务。参见 Spring 的 DataSourceTransactionManagerspring-doc.cadn.net.cn