Spring中事务的传播行为
Spring事务传播行为
事务传播行为 指的是:在多个事务方法相互调用时,事务应该如何在这些方法间传播。简单来说,就是一个带有事务的方法(比如方法A)调用另一个带有事务的方法(比如方法B)时,方法B是沿用方法A的事务,还是自己新开一个事务,或者以非事务方式运行?这就是由事务传播行为来决定的。Spring框架在 Propagation 枚举中定义了7种传播行为。
7种传播行为详解
假设我们有两个方法:methodA() 和 methodB()。methodA 调用了 methodB。我们来分析不同传播行为下 methodB 的表现。
1. REQUIRED(默认)
语义:支持当前事务。如果当前没有事务,就新建一个事务。
场景:最常用的设置,适用于大多数情况。
举例:
如果
methodA开启了事务,则methodB会加入这个事务。如果
methodA没有事务,则methodB会新建一个事务。
效果:两者处于同一个事务中,任何一个方法抛出异常,整个事务都会回滚。
2. SUPPORTS
语义:支持当前事务。如果当前没有事务,就以非事务方式执行。
场景:该方法可以“适应”调用方,对事务要求不严格,比如查询操作。
举例:
如果
methodA有事务,methodB则在该事务中运行。如果
methodA没有事务,methodB也以非事务方式执行。
3. MANDATORY
语义:支持当前事务。如果当前没有事务,就抛出异常。
场景:该方法必须在一个已存在的事务中运行,否则认为是编程错误。
举例:
如果
methodA有事务,methodB正常加入。如果
methodA没有事务,methodB将抛出IllegalTransactionStateException。
4. REQUIRES_NEW
语义:新建事务。如果当前存在事务,则把当前事务挂起。
场景:希望新方法的事务完全独立,不受外层事务失败的影响,比如日志记录(即使业务失败,日志仍需记录)。
举例:
无论
methodA是否有事务,methodB都会启动一个新事务。methodB新事务的提交和回滚,与methodA的事务完全独立。methodA的事务会被挂起,等methodB的事务执行完毕后再恢复。
5. NOT_SUPPORTED
语义:以非事务方式执行。如果当前存在事务,则把当前事务挂起。
场景:该方法不应在事务中运行,例如执行一些不需要事务的、耗时较长的操作。
举例:
无论
methodA是否有事务,methodB都会以非事务方式执行。如果
methodA有事务,它会被挂起。
6. NEVER
语义:以非事务方式执行。如果当前存在事务,则抛出异常。
场景:严格要求不能在事务中运行的方法,与
MANDATORY相反。举例:
如果
methodA没有事务,methodB正常以非事务方式执行。如果
methodA有事务,methodB将抛出异常。
7. NESTED
语义:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与
REQUIRED类似的操作。场景:一个复杂事务中可以分支出多个子事务,子事务可以独立回滚而不影响主事务。
举例:
如果
methodA有事务,Spring会启动一个嵌套事务(在数据库中通常通过保存点Savepoint实现)。如果
methodB失败回滚,只会回滚到它自己的保存点,不会影响methodA的后续操作。但methodA的失败会导致methodB也回滚。注意:这个行为需要JDBC 3.0以上驱动和支持保存点的数据库(如MySQL的InnoDB引擎)。
