Spring事务传播机制
Spring中提供了事务的增强功能,即事务的传播,不属于数据库,是Spring框架提供的,不同的事务传播行为,带来不同的事务特性,Spring提供了其中事务传播行为,在Propagation
枚举中进行了定义。
事务传播行为
七种事务传播行为:
事务传播行为类型 | 说明 |
---|---|
Propagation.REQUIRED |
如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。默认的。 |
Propagation.SUPPORTS |
支持当前事务,如果当前没有事务,就以非事务方式执行。 |
Propagation.MANDATORY |
使用当前的事务,如果当前没有事务,就抛出异常。 |
Propagation.REQUIRES_NEW |
新建事务,如果当前存在事务,把当前事务挂起。 |
Propagation.NOT_SUPPORTED |
以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 |
Propagation.NEVER |
以非事务方式执行,如果当前存在事务,则抛出异常。 |
Propagation.NESTED |
如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。 |
验证例子
REQUIRED
如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。
1 | // 业务方法一 serviceOne |
分析:
- 如果调用方法上没有添加事务,则1,2两个插入分别会创建一个自己的事务,进行各自的数据库操作,即1插入失败回滚,2插入成功。
- 我们想要的结果是1和2要么全部成功,要么全部失败,这时只需要在调用的方法上添加事务即可
@Transactional(rollbackFor = Exception.class)
,让两个方法都加到此事务中处理。
REQUIRES_NEW
新建事务,如果当前存在事务,把当前事务挂起,在自己的事务中执行。
调用者不加事务
测试:
1 | /** 测试1:外围方法没开启事务,并抛出异常 均会插入数据*/ |
分析:
- 外围方法不加事务,并有异常,那么两个方法在各自独立的事务中执行;
- 调用异常的事务也只对本方法回退,不会影响整个调用者。
调用者添加事务
测试:
1 |
|
分析:
- 调用者有事务,并且抛出异常了,只会回退本方法中的事务,两个子方法是独立的事务运行,因此不会回退;
- 如果调用的业务方法中抛出异常了,调用者也会捕获,因此它的事务也会回退。
NESTED
如果当前存在事务,则在嵌套事务内执行。
分析:
- 外部调用者如果不加事务,那么表现与REQUIRED方式一样;
- 外部调用者添加了事务,被调用的方法则是其子事务;
- 调用者异常回退,子事务也会回退;
- 子事务中如果有异常,向上抛,则事务回退,自己消化掉,则只会回退子事务。
对比
NESTED和REQUIRED修饰的内部方法都属于外围方法事务,如果外围方法抛出异常,这两种方法的事务都会被回滚。但是REQUIRED是加入外围方法事务,所以和外围事务同属于一个事务,一旦REQUIRED事务抛出异常被回滚,外围方法事务也将被回滚。而NESTED是外围方法的子事务,有单独的保存点,所以NESTED方法抛出异常被回滚,不会影响到外围方法的事务。
NESTED和REQUIRES_NEW都可以做到内部方法事务回滚而不影响外围方法事务。但是因为NESTED是嵌套事务,所以外围方法回滚之后,作为外围方法事务的子事务也会被回滚。而REQUIRES_NEW是通过开启新的事务实现的,内部事务和外围事务是两个事务,外围事务回滚不会影响内部事务。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 张国丰!
评论