本文记录几种主要的Spring事务传播行为。
Spring事务传播行为
1.PROPAGATION_REQUIRED(默认)
在外围方法开启事务的情况下Propagation.REQUIRED
修饰的内部方法会加入到外围方法的事务中,所有Propagation.REQUIRED
修饰的内部方法和外围方法均属于同一事务,只要一个方法回滚,整个事务均回滚。
2.PROPAGATION_NESTED(嵌套子事务)
在外围方法开启事务的情况下Propagation.NESTED
修饰的内部方法属于外部事务的子事务,外围主事务回滚,子事务一定回滚,而内部子事务可以单独回滚而不影响外围主事务和其他子事务。
3.PROPAGATION_REQUIRES_NEW (独立新事务)
在外围方法开启事务的情况下Propagation.REQUIRES_NEW
修饰的内部方法依然会单独开启独立事务,且与外部方法事务也独立,内部方法之间、内部方法和外部方法事务均相互独立,互不干扰。
4.PROPAGATION_NOT_SUPPORTED
如果没有,就以非事务方式执行(如果发现方法A没有开启事务,则方法B也不开启事务);如果有,就将当前事务挂起。(方法A的事务挂起,而方法B非事务的状态运行完,再继续方法A的事务。)这就是 PROPAGATION_NOT_SUPPORTED,这种方式非常强硬,没有就没有,有我也不支持你,把你挂起来,不鸟你。
5. PROPAGATION_SUPPORTED
如果没有,就以非事务方式执行(如果发现方法A没有开启事务,则方法B也不开启事务);如果有,就加入当前事务。(方法B看到自己已经运行在方法A的事务内部,就不再起新的事务,直接加入方法A)。这就是 PROPAGATION_SUPPORTS,这种方式非常随意,没有就没有,有就有,有点无所谓的态度,反正我是支持你的。
6.PROPAGATION_NEVER
如果没有,就以非事务方式执行(如果发现方法A没有开启事务,则方法B也不开启事务);如果有,就抛出异常(如果发现方法A有开启事务,则方法B直接抛出异常)。这就是 PROPAGATION_NEVER,这种方式更猛,没有就没有,有了反而报错,确实够牛的,它说:我从不支持事务!
7.PROPAGATION_MANDATORY
如果没有,就抛出异常;如果有,就使用当前事务。这就是 PROPAGATION_MANDATORY
,这种方式可以说是牛逼中的牛逼了,没有事务直接就报错,确实够狠的,它说:我必须要有事务!
记录一片比较好的文章参考方便复习:https://segmentfault.com/a/1190000013341344#comment-area
问题记录
在外围方法开启事务的前提下,内部事务的传播行为REQUIRED,此时如果外部方法捕获内部方法的异常直接吞掉,外部事务在提交的时候会报Transaction rolled back because it has been marked as rollback-only。这是因为内部事务在回滚的时候已经将rollback-only设置为true,那么外部事务切面在执行的时候虽然没有捕获到异常但是判断这个状态为true,则进行回滚。
应用场景
在乐其的工作中,通常会有处理一张数据量超大的表的需求。
通常我们为了避免大事务会将这个事务分成几个独立事务分别进行提交,并汇总执行的结果。
其中一个失误发生异常通过try catch捕获,不影响其他事务。
1.内部方法添加独立事务注解:
1 | (rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW) |
2.外部方法添加事务:
1 | (rollbackFor = Exception.class,propagation = Propagation.REQUIRED) |