Spring事务传播行为?失效情况?(详解)
事务传播行为指的就是当一个事务方法被另一个事务方法调用时这个事务方法应该如何进行。
Spring中有七种事务的传播行为,分别是:required、requires_new、supports、not_supported、nested、mandatory、never
required
如果当前没事务,就新建一个事务;如果已经存在事务,则加入该事务
外围A方法,内围B、C方法required
-
A方法无事务(外围方法无事务,内围方法独立回滚,互不干扰)
-
-
A方法抛出异常,B、C不会回滚
-
C方法抛出异常,C单独回滚,A、B不会回滚
-
-
A方法有事务 (内外围方法属于同一个事务,一个回滚,全部回滚)
-
-
A方法抛出异常,A回滚,B、C也回滚
-
C方法抛出异常,C回滚,A感知到异常,A回滚,B也回滚
-
C方法抛出异常并被Acatch,C回滚,A未感知异常,但A、B、C同事务,A回滚,B也回滚
-
required_new
新建事务
外围A方法,内围B、C方法required_new
-
A方法无事务(外围方法无事务,内围方法独立回滚,互不干扰,同required外围方法无事务)
-
-
A方法抛出异常,B、C不会回滚
-
C方法抛出异常,C单独回滚,A、B不会回滚
-
-
A方法有事务 (内围方法之间、内外围方法之间均相互独立,互不干扰,除非内围方法抛出异常被外围方法感知到)
-
-
A方法抛出异常,B、C不会回滚
-
C方法抛出异常,C回滚,A感知到异常并抛出,A回滚,B不回滚
-
C方法抛出异常并被Acatch,C回滚,A未感知异常,A不回滚,B不回滚
-
nested
如果当前没有事务,就新建一个事务;如果已经存在事务,则作为该事务的子事务
外围A方法,内围B、C方法nested
-
A方法无事务(外围方法无事务,内围方法独立回滚,互不干扰,同required外围方法无事务)
-
-
A方法抛出异常,B、C不会回滚
-
C方法抛出异常,C单独回滚,A、B不会回滚
-
-
A方法有事务 (外围方法回滚,内围方法全部回滚;内围方法回滚,不影响外围方法和其他内围方法,除非内围方法抛出的异常被外围方法感知到)
-
-
A方法抛出异常,A回滚,B、C是A的子事务,B、C回滚
-
C方法抛出异常,C回滚,A感知到异常并抛出,A回滚,B是A的子事务,B回滚
-
C方法抛出异常并被Acatch,C回滚,A未感知异常,A不回滚,B不回滚
-
注意:如果C方法产生的异常被C自身catch,则C方法即使加了事务,也不会回滚!这是事务失效的一个场景。
-
support
支持当前事务,如果当前没事务,则无事务运行 -
mandatory
使用当前事务,如果当前没事务,则抛出异常 -
not_support
不支持事务,如果当前有事务,则不使用 -
never
不支持事务,如果当前有事务,则抛出异常
事务传播行为有什么用?
主要作用就是:控制事务边界
拿PROPAGATION NESTED
来举例。如果外层事务失败,则会回滚内层事务,内层事务失败不影响外层事务。
可以发现,外层事务失败会影响到内层事务,即外层到内层之间是没有边界的,但内层失败则不影响外层,说明内层往外层之间事务是有边界的,使得影响无法传播出去。
事务传播行为可以帮助处理错误情况,灵活的选择回滚整个事务或仅回滚当前方法的事务
Spring 事务在什么情况下会失效?
一般而言失效的情况都是用了声明式事务即 @Transactional
注解
-
由于Spring的事务是基于AOP的方式结合动态代理来实现的。因此事务方法一定要是public的,这样才能便于被Spring做事务的代理和增强。
-
若没有正确地设置
@Transactional
注解中的rollbackFor
属性,那么只有当抛出RuntimeException
或Error
时,事务才会回滚。 -
如果事务代码抛错,但是被捕获了,但仅仅记录了日志,这样事务无法正常获取到错误,因此不会回滚。
-
非事务方法调用事务方法,是不会走代理的,因为事务是基于动态代理实现的
-
事务传播行为不对
-
没有被
Spring
管理