本文主要介绍了Spring事务传播性的相关知识。
Spring中定义了7种事务传播性:
在Spring环境中,含有事务的方法嵌套调用,事务是如何传递的规则,以及每种规则是如何开展工作的。文章还提到每种事务传播性是如何使用的,方便读者依据实际的场景,使用不同的事务规则。
Spring 事务传播性是指, 在Spring的环境中,当多个含有事务的方法嵌套调用时,每个事务方法都处于自己事务的上下文中,其提交或者回滚行为应该如何处理。
通俗讲,就是当一个事务方法调用另外一个事务方法时,事务如何跨上下文传播。
1)当事务方法A调用事务方法B时,事务方法B是合并到事务方法A中,还是开启新事务?
2)当事务方法B抛出异常时 ,在合并事务或者开启新的事务的场景中,事务的回滚是如何处理的 ?
以上事务的处理规则,都取决于事务传播级别的设置。
事务的传播行为,主要分为三种类型,分别是:支持当前事务、不支持当前事务、嵌套事务。
REQUIRED:默认的事务传播级别,表示如果当前方法已在事务内,该方法就在当前事务中执行,否则,开启一个新的事务并在其上下文中执行。
SUPPORTED:当前方法在事务内,则在其上下文中执行该方法,否则,开启一个新的事务。
MANDATORY:必须在事务中执行,否则,将抛出异常。
REQUIRES_NEW:无论当前是否有事务上下文,都会开启一个事务 。如果已经有一个事务在执行 ,则正在执行的事务将被挂起 ,新开启的事务会被执行。
事务之间相互独立,互不干扰。
NOT_SUPPORTED:不支持事务,如果当前存在事务上下文,则挂起当前事务,然后以非事务的方式执行。
NEVER:不能在事务中执行,如果当前存在事务上下文,则抛出异常。
NESTED:嵌套事务,如果当前已存在一个事务的上下文中,则在嵌套事务中执行,如果抛异常,则回滚嵌套事务,而不影响其他事务的操作。
默认的事务传播行为,保证多个嵌套的事务方法在同一个事务内执行,并且同时提交,或者出现异常时,同时回滚。
这个机制可以满足大多数业务场景。
例子 :
图片
1)类TestAService的方法通过声明式事务的方式,加上了事务注解@Transactional ,并设置事务的传播性为REQUIRED。
2)调用者调用TestAService的A方法时,如果调用者没有开启事务,那么A方法会开启一个事务。
A方法的具体执行过程如下 :
a. 执行insert,但没有提交;
b.调用TestBServcie的B方法,由于B方法也声明了事务,并且传播性是REQUIRED,所以方法B的事务,合并到方法A开启的事务中。
c.方法B执行insert操作,此时也没有提交。
3)由于这两个方法的操作都在同一个事务中执行,当这两个方法所有操作执行成功之后,提交事务。
嵌套调用链路:
当方法B 执行时抛出了 Exception 异常后,事务是如何处理的 ?
1)方法B声明了事务,insert操作会回滚
2)由于方法A和方法B 同属一个事务,方法A也会执行回滚,由此说明该规则保证了事务的原子性。
嵌套调用,异常后的链路:
如果 方法B 抛出异常后,方法A 使用 try-catch 处理了方法B的异常(如下代码),并没有向外抛出,此时事务又如何处理的 ?
方法A也会回滚。
从事务的特性我们可知,事务具有原子性。方法A和方法B同属一个事务,当方法B抛出异常,触发回滚操作后,整个事务的操作都会回滚。
因此,Spring 在处理事务过程中,当事务的传播性设置为REQUIRED,在整个事务的调用链上,任何一个环节抛出的异常都会导致全局回滚。
每次都开启一 个新的事务。
例子:
上面例子中,方法B的传播性设置为 REQUIRES_NEW,方法A仍然是REQUIRED,当A调用B时,具体调用链路如下:
具体执行过程:
当 方法B 执行时抛出了异常,会发生什么?
方法B的insert操作会被回滚掉,方法A不受影响。但这里有个前提,方法A需要try-catch方法B的异常,使其异常不会往上传递,从而导致方法A接收到异常,导致回滚。
当外层方法A存在事务,方法B加入到当前事务中,以事务的方式执行。
当外层方法A不存在事务,方法B不会创建新的事务,以非事务的方式执行。
例子1:
以上例子,方法A没有加事务注解,方法B的加了事务注解,并且传播为SUPPORTS。
具体执行过程:
例子2:
以上例子,方法A和B都加上了事务注解,其中方法A的传播性为REQUIRED,方法B的传播性为SUPPORTS。
具体执行过程:
不支持事务。
如果外层方法存在事务,则挂起外层事务,以非事务方式执行,执行完毕后,恢复外层事务。
例子:
以上例子:方法A和B都加上了事务注解,方法A的传播性为REQUIRED,方法B为NOT_SUPPORTED。
具体执行过程:
调用链路过程:
不支持事务
当外层方法A开启了事务,方法B抛出异常
例子:
以上代码,两个方法都打上了事务注解,方法A的传播性是REQUIRED,方法B的传播性是NEVER。
具体执行过程:
必须在事务中执行。
如果外层方法A没有开启事务,方法B抛出异常。
如果外层方法A开启了事务,方法B加入事务,方法A&B在同一事务中执行。
例子:
以上例子,方法A没有加事务注解,方法B 的传播性为 MANDATORY。
具体执行过程:
嵌套事务
例子:
以上例子,方法A的传播性为REQUIRED,方法B为NESTED。
具体执行过程:
调用链路:
本文解释了Spring框架中的事务传播性,即多个业务方法之间调用时事务如何处理的规则。Spring提供了七种传播级别,如
PROPAGATION_REQUIRED、
PROPAGATION_REQUIRES_NEW等。
每种级别都有适用场景和限制,本文提供了一些示例,介绍了声明式事务如何使用,每种事务的规则,产生哪种行为,当方法抛出异常时,事务的提交和回滚是如何被处理的。正确处理事务对于任何企业级应用程序都是必要的,了解Spring事务传播性是构建高效、可靠和可扩展应用程序的关键。