Transaction Propagation

本节描述了 Spring 中事务传播的一些语义。请注意,本节并不是对事务传播的正确介绍。相反,它详细介绍了 Spring 中有关事务传播的一些语义。 在 Spring 管理的事务中,请注意物理事务和逻辑事务之间的差异,以及传播设置如何应用于此差异。

Understanding PROPAGATION_REQUIRED

tx prop required

PROPAGATION_REQUIRED 强制执行物理事务,如果当前作用域中尚未存在事务,则强制执行本地事务,或者参与为更大作用域定义的现有“外部”事务。在同一线程中的调用栈常用排列中,这是一个很好的默认值(例如,将任务委托给几个存储库方法的服务外观,其中所有基础资源都必须参与服务级别事务)。

默认情况下,参与的事务将加入外部范围的特性,静默忽略本地隔离级别、超时值或只读标志(如果有)。如果您希望在参与具有不同隔离级别的现有事务时拒绝隔离级别声明,请考虑将 validateExistingTransactions 标志切换到 true 您的事务管理器上。此非宽容模式还拒绝只读不匹配(即,内部读写事务尝试参与只读外部范围)。

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

然而,在内部事务作用域设置回滚状态标记的情况下,外部事务尚未决定是否回滚,因此由内部事务作用域(无声触发)触发的回滚是意外的。这时会抛出相应的 UnexpectedRollbackException。这是预期的行为,因此事务的调用者永远不会被误导为以为在实际没有提交的情况下执行了提交。因此,如果一个内部事务(外部调用者不知道)将事务无声地标记为仅回滚,则外部调用者仍然调用提交。外部调用者需要收到 UnexpectedRollbackException 才能明确指示已经执行了回滚。

Understanding PROPAGATION_REQUIRES_NEW

tx prop requires new

PROPAGATION_REQUIRED 相反,PROPAGATION_REQUIRES_NEW 总是为每个受影响的事务作用域使用独立的物理事务,永远不会参与外部作用域的现有事务。在这样的安排中,底层资源事务是不同的,因此可以独立提交或回滚,外部事务不受内部事务回滚状态的影响,并且内部事务的锁在其完成之后立即释放。这样的独立内部事务还可以声明其自己的隔离级别、超时和只读设置,而不继承外部事务的特征。

连接至外部事务的资源将保持绑定状态,而内部事务获取它自己的资源,例如新的数据库连接。如果多个线程具有活动外部事务并等待为其内部事务获取新连接,这可能会导致连接池耗尽,并可能导致死锁,因为连接池无法再分配任何此类内部连接。除非您的连接池已适当调整大小,且至少比并发线程数多 1,否则请不要使用 PROPAGATION_REQUIRES_NEW

Understanding PROPAGATION_NESTED

PROPAGATION_NESTED 使用单个物理事务和可以回滚到多个保存点。这种部分回滚允许内部事务作用域触发其作用域的回滚,同时外部事务能够继续物理事务,而不管某些操作已被回滚。此设置通常映射到 JDBC 保存点,因此它仅适用于 JDBC 资源事务。请参阅 Spring 的https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/jdbc/datasource/DataSourceTransactionManager.html[DataSourceTransactionManager]。