为什么有事务传播行为
Spring中,开启事务的常见方法是添加@Transactional注解,通过AOP实现事务管理。
但问题是,我们可能在不同类的多个互相调用的方法上加上这个注解,这样我们开发者对底层事务切面的逻辑就不清楚了。所以Spring定义了事务的传播行为这个东西帮我们解释了这种情况底层会怎么运作。
所以在数据库里是没有事务传播行为这个概念的,这个概念是Spring帮我们指定的。
什么是事务传播行为
PROPAGATION_REQUIRED
默认的行为。如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。
此处是同一个事务,假如内层方法抛异常,则必须回滚,否则spring会帮你抛一个xxx marked as roll-back 啥啥啥的异常。
PROPAGATION_SUPPORTS
支持当前事务,如果当前没有事务,就以非事务方式执行。这里没什么特别指出,按字面意思理解即可。
PROPAGATION_MANDATORY
使用当前的事务,如果当前没有事务,就抛出异常。这里没什么特别指出,按字面意思理解即可。
PROPAGATION_REQUIRES_NEW
新建事务,如果当前存在事务,把当前事务挂起。此处的两个事务互不影响,互不干扰,独立决定是否回滚。
PROPAGATION_NOT_SUPPORTED
以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER
以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED
如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。
这里底层事务回滚了,外层事务catch了,则不会影响外层事务。但是如果外层事务回滚了,底层事务也必须回滚。
额外补充
要注意一个地方:事务的传播行为是基于AOP的,AOP是基于代理模式的,假如直接在同一个类中方法调用方法,事务是没有传播行为的,因为这时候代理模式invoke了一个被代理对象的方法,被代理对象内部如何调用它是不关心的,这也是一个坑吧,工作中大家遇到的时候要注意。
基于上面的理论,我们其实还会发现假如我们调用一个没有标注@Transactional注解的方法,该方法内部调用使用了@Transactional注解的方法,这时候事务会失效,原理也是和之前一样。整个类被包装成了代理对象,代理对象会invoke被代理对象的方法,而方法的内部调用是被代理对象的原生调用,不会封装事务。所以假如你调用了 没有标注@Transactional注解的方法,会发现被标注了@Transactional注解的方法的事务也失效了。