事务传播
本节描述了 Spring 中事务传播的一些语义。请注意,本节不是关于事务传播的正式介绍。相反,它详细说明了 Spring 中关于事务传播的一些语义。
在 Spring 管理的事务中,请注意物理事务和逻辑事务之间的区别,以及传播设置如何应用于此区别。
理解PROPAGATION_REQUIRED
PROPAGATION_REQUIRED
强制执行物理事务,如果当前范围内尚不存在事务,则在本地强制执行,或者参与为更大范围定义的现有“外部”事务。在同一线程内的常见调用栈排列中,这是一个很好的默认设置(例如,服务外观委托给几个存储库方法,其中所有底层资源都必须参与服务级事务)。
默认情况下,参与的事务会加入外部范围的特性,默默地忽略本地隔离级别、超时值或只读标志(如果有)。如果您希望在参与具有不同隔离级别的现有事务时拒绝隔离级别声明,请考虑在您的事务管理器上将validateExistingTransactions 标志切换为true 。此非宽容模式还会拒绝只读不匹配(即,尝试参与只读外部范围的内部读写事务)。 |
当传播设置是PROPAGATION_REQUIRED
时,将在应用该设置的每个方法上创建一个逻辑事务范围。每个此类逻辑事务范围都可以单独确定回滚状态,外部事务范围在逻辑上独立于内部事务范围。在标准PROPAGATION_REQUIRED
行为的情况下,所有这些范围都映射到相同的事务。因此,在内部事务范围内设置的回滚标记确实会影响外部事务实际提交的机会。
但是,在内部事务范围设置回滚标记的情况下,外部事务尚未决定是否回滚,因此回滚(由内部事务范围静默触发)是意外的。此时会抛出相应的UnexpectedRollbackException
。这是预期的行为,以便事务的调用者永远不会被误导地认为已执行提交,而实际上并没有执行。因此,如果内部事务(外部调用者不知道)静默地将事务标记为回滚,则外部调用者仍然会调用提交。外部调用者需要接收UnexpectedRollbackException
以明确指示已执行回滚。
理解PROPAGATION_REQUIRES_NEW
PROPAGATION_REQUIRES_NEW
与PROPAGATION_REQUIRED
相反,始终为每个受影响的事务范围使用独立的物理事务,从不参与外部范围的现有事务。在这种安排中,底层资源事务是不同的,因此可以独立提交或回滚,外部事务不受内部事务的回滚状态的影响,并且内部事务的锁在其完成之后立即释放。此类独立的内部事务还可以声明自己的隔离级别、超时和只读设置,并且不继承外部事务的特性。
附加到外部事务的资源将保留在那里,而内部事务获取自己的资源,例如新的数据库连接。这可能导致连接池耗尽,并且如果多个线程具有活动外部事务并等待获取其内部事务的新连接,而池不再能够分发任何此类内部连接,则可能导致死锁。除非您的连接池大小合适,并且至少比并发线程数多 1,否则请勿使用PROPAGATION_REQUIRES_NEW 。 |
理解PROPAGATION_NESTED
PROPAGATION_NESTED
使用单个物理事务和多个它可以回滚到的保存点。此类部分回滚允许内部事务范围触发其范围的回滚,即使某些操作已回滚,外部事务也能够继续物理事务。此设置通常映射到 JDBC 保存点,因此它仅适用于 JDBC 资源事务。请参阅 Spring 的DataSourceTransactionManager
。