Spring事务的传播行为
2021-02-02 本文已影响0人
文景大大
一、什么是Spring的事务传播性
当多个事务方法嵌套在一起的时候,外层方法的事务特性是否应该传播给内层的方法?研究这一传播特性的机制就是Spring事务的传播性。Spring为了满足不同业务场景下的需求,定义了七种传播行为。
二、Spring事务的传播行为有哪些
2.1 REQUIRED
这是Spring默认的事务传播行为,当外层调用方法开启了事务时,那么当前方法就加入到外层方法的事务中;如果外层调用方法没有开启事务,那么当前方法就自己开启一个事务。
这是绝大多数业务场景需要使用的事务传播行为,可以保证多个内层的事务方法和外层事务方法一起提交,或者一起回滚 ,保证多个事务方法的数据一致性。
@Slf4j
@Service
public class ServiceA {
@Autowired
private ServiceB serviceB;
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public void methodA(){
// 1.模拟往数据库插入操作
log.info("开始调用methodB方法");
serviceB.methodB();
}
}
@Slf4j
@Service
public class ServiceB {
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public void methodB(){
// 2.模拟往数据库的更新操作
log.info("完成methodB的更新操作");
}
}
以上代码示例中:
- 如果methodA没有开启事务,那么methodB会自己开启一个事务,methodB如果发生异常,仅自己的2操作会回滚,methodA的1操作不会回滚;
- 如果methodA开启了事务,那么methodB会加入methodA的事务中,methodB如果发生异常,那么自己的2操作会回滚,methodA的1操作也会回滚;
- 如果methodA开启了事务,且methodA对methodB的异常进行try-catch,methodB如果发生异常,操作2和操作1还是都会回滚;
2.2 REQUIRES_NEW
每次都是开启一个新的事务,如果外层调用方法已经开启了事务,就把外层方法的事务挂起,执行内层方法的事务,等到执行完毕后再恢复外层的事务。
我们还是以上面的例子来讲,假设methodB开启的传播行为是REQUIRES_NEW
,那么:
- 如果methodA没有开启事务,那么methodB会自己开启一个事务,methodB如果发生异常,仅自己的2操作会回滚,methodA的1操作不会回滚;
- 如果methodA开启了事务,那么methodB会挂起methodA的事务,重新开启自己的事务,methodB如果发生异常,那么自己的2操作会回滚,methodA的1操作也会回滚;
- 如果methodA开启了事务,且methodA对methodB的异常进行try-catch,methodB如果发生异常,那么自己的2操作会回滚,methodA的1操作不会回滚;
2.3 SUPPORTED
如果外层调用方法开启了事务,那么内层方法就加入外层方法的事务中;但是,如果外层调用方法没有开启事务,那么内层方法也以非事务的方式执行。
我们还是以上面的例子来讲,假设methodB开启的传播行为是SUPPORTED
,那么:
- 如果methodA没有开启事务,那么methodB就以非事务的方式运行;
- 如果methodA开启了事务,那么methodB会加入methodA的事务中,methodB如果发生异常,那么自己的2操作会回滚,methodA的1操作也会回滚;
- 如果methodA开启了事务,且methodA对methodB的异常进行try-catch,methodB如果发生异常,操作2和操作1还是都会回滚;
2.4 NOT_SUPPORTED
不管外层调用方法是否开启了事务,内层方法都以非事务的方式运行;
我们还是以上面的例子来讲,假设methodB开启的传播行为是NOT_SUPPORTED
,那么:
- 如果methodA没有开启事务,那么methodB就以非事务的方式运行;
- 如果methodA开启了事务,那么methodB会以非事务的方式运行,methodB如果发生异常,那么自己的2操作不会回滚,methodA的1操作会回滚;
- 如果methodA开启了事务,且methodA对methodB的异常进行try-catch,methodB如果发生异常,那么自己的2操作不会回滚,methodA的1操作会回滚;
2.5 NEVER
内层方法不允许外层方法开启事务,否则就会报错。
2.6 MANDATORY
内层方法要求外层调用方法必须开启事务,否则就报错。
2.7 NESTED
基本使用和REQUIRED
一致,但是不同点在于,会在声明NESTED
的事务方法前建立一个保存点,这个保存点之前的操作不再回滚。
三、常用的Spring事务传播行为总结
通常的业务使用中,我们最长使用的就是REQUIRED
和REQUIRES_NEW
:
-
REQUIRED
的使用适合那种多个业务操作顺序执行的流程,这几个业务操作需要保证事务的原子性,不能出现数据不一致的情况。 -
REQUIRES_NEW
的使用场景则是需要内层方法出错了不会影响外部调用层的其它内容,这个内层方法有可能是不太重要的日志打印、埋点记录等。
其它传播行为使用的场景极少,作为了解即可。