接着上一篇讲的,确保数据库连接和操作没有问题之后,开始对事务传播行为进行测试,在浏览器中输入路径http://localhost:8080/user/save,来看一下测试结果:
从控制台中可以看到Hibernate打印出了一条insert语句,证明插入了一条数据,但是为什么doA()方法和doB()方法都执行了却只插入了一条数据呢?那插入的这条数据又是哪个方法里面的呢?我们先到数据库查询一下:
可以明显的看出,这条数据是doB()方法里面插入的,而doA()中插入的数据被回滚了,这是因为我们在doB()方法中加入ROPAGATION_REQUIRES_NEW传播行为,doB()创建了属于自己的事务,挂起了doA()中的事务,所以事务B提交了,而在doA()方法中加入的是ROPAGATION_REQUIRED传播行为,事务A因为执行异常,不会再创建新的事务,因此插入的数据被回滚了。
注意:在上面的实例中,我们没有把doB()方法放在UserController中,在doA()方法中直接调用doB()方法,而是放在了BusinessServiceImpl中,这是因为spring通过扫描所有含有注解的@Transactional的方法,使用aop形成事务增强advise。但是加入增强时是通过代理对象调用方法的形式加入的,如果将doB()方法放在doA()方法直接调用时,在调用doB()方法的时候是通过当前对象来调用doB()方法的,而不是通过代理来调用的doB()方法,这个时候doB()方法上加的事务注解就失效了不起作用。
如果我们将doB()方法做下修改,改为第一种传播行为ROPAGATION_REQUIRED:
再来看测试结果:
可以明显的看出,一条数据都没有插入到数据库中,这是为什么呢?因为这两个方法使用的都是第一种传播行为PROPAGATION_REQUIRED ,doB()方法被加入到doA()的事务中,doA()执行时抛出了异常,因为doB()和doA()同属于一个事务,则执行操作被一起回滚了。其实在doB()中我们不加入注解,也等同PROPAGATION_REQUIRED的效果,因为Spring中事务传播行为默认为PROPAGATION_REQUIRED方式,它也是我们最常用的一种方式。
接下来我们再来看看第五种传播行为PROPAGATION_NOT_SUPPORTED,我们同样修改doB()方法,将@Transactional注解中的propagation改为Propagation.NOT_SUPPORTED,再看测试结果:
结果和上面第一种方式一样,doB()方法成功插入了数据,而doA()方法中插入的数据被回滚了。这是因为传播行为PROPAGATION_NOT_SUPPORTED是doB()以非事务执行的,并且提交了。所以当doA()的事务被回滚时,doB()的操作没有被回滚。
其他的传播行为就不一一列举了,机制是差不多的。若大家还想更深入的了解事务传播行为,推荐给大家一篇文章,写的非常详细:https://segmentfault.com/a/1190000013341344