临时起意对传播行为的几种属性做了一下测试。
首先看下面这张图对事务的其中传播属性做的说明(前两种应该用的比较多),下面对每种传播行为的结果做一下举例
下面的实验以这两个service中的addconsumer1和decreaseStock方法以及stockMapper
中的decreaseStock为核心进行实验,具体做法是在StockServiceImpl的一个
decreaseStock方法中(外部事务)调用了stockMapper.decreaseStock方法来让库存减一,
且调用addconsumer1方法(内部事务)来添加用户
1.REQUIRED
如果当前存在事务,那么就加入该事务:比如下图中两个方法都用@Transactional修饰,那么
执行的时候这两个事务会合并成一个事务。下图测试的结果是当外部事务中发生异常,内部
事务也会跟着回滚。数据表不发生变化
如果当前没有事务,则创建一个新事务:还是下图的例子,当@decreaseStock方法不加
@Transaction注解的时候,就会出现第一次的减库存decreaseStock执行成
功,addconsumer1由于是自己创建的事务,所以数据也添加成功,而第二次减库存操作之前由
于发生了运行时异常,所以不生效
2.REQUIRES_NEW
创建一个新的事务,如果当前存在事务,则把当前事务挂起:还是下面的例子:还是1中的例子,
只是把
@Transaction中的propagation改了成了REQUIRES_NEW,此时外部事务decreaseStock
发生了异常回滚,不会影响到内部事务,因为addconsumer1创建了一个新事务
3.SUPPORTS
如果当前存在事务,就加入该事务,如果没有事务,就以非事务的方式继续运行:比如此时
addconsumer1方法设置了Propagation.SUPPORTS,然后decreaseStock把
@Transacitonal注解注释掉了,那么此时就相当于这两个方法都不进行事务处理。那么下图
的结果就是第一次的decreaseStock和addconsumer1生效,第二次的decreaseStock不生
效。如果deceaseStock方法加了@Transactional注解开启了事务,那么此时两个方法走同
一个事务
4.MANDATORY
有事务运行就加入,没有就抛异常。比如addconsumer1方法开启了MANDATORY级别的传
播属性,而decreaseStock方法没加@Transactional注解,此时运行就会报错,因为
addconsumer1方法没有运行在事务内
5.NOT_SUPPORTED
以非事务方式运行,如果当前存在事务,则将该事务挂起:我在内部事务方法中设置了
NOT_SUPPORTED传播级别,通过debug可以发现,外部事务还没提交,内部addconsumer1
方法已经对数据库的数据进行了修改
6.NEVER
如果当前存在事务就抛出异常,这个就很好理解不做演示了
7.NESTED
外部有事务,此时内部事务作为当前事务的嵌套事务来执行,发生的异常在外部捕获,此时,addconsumer1对数据库的修改回滚,decreaseStock正常执行。
这里可以特别注意一下和两个方法都设置成REQUIRED的区别:同样的测试代码,如果都换成REQUIRED,此时会因为内部事务异常没有在内部捕获,而导致内部和外部整个事务回滚,也就是说decreaseStock和addconsumer1都不生效