-SpringBoot系列教程之事务传递属性
对于mysql而言,关于事务的主要知识点可能几种在隔离级别上;在Spring体系中,使用事务的时候,还有一个知识点事务的传递属性同样重要,本文将主要介绍7中传递属性的使用场景
I.配置
本文的case,将使用声明式事务,首先我们创建一个SpringBoot项目,版本为2.2.1.RELEASE,使用mysql作为目标数据库,存储引擎选择Innodb,事务隔离级别为RR
1.项目配置
在项目pom.xml文件中,加上spring-boot-starter-jdbc,会注入一个DataSourceTransactionManager的bean,提供了事务支持
2.数据库配置
进入spring配置文件application.properties,设置一下db相关的信息
3.数据库
新建一个简单的表结构,用于测试
II.使用说明
0.准备
在正式开始之前,得先准备一些基础数据
其次测试事务的使用,我们需要额外创建一个测试类,后面的测试case都放在类PropagationSample中;为了使输出结果更加友好,提供了一个封装的call方法
1.REQUIRED
也是默认的传递属性,其特点在于
如果存在一个事务,则在当前事务中运行如果没有事务则开启一个新的事务使用方式也比较简单,不设置
Transactional注解的propagation属性,或者设置为REQUIRED即可上面就是一个基础的使用姿势
输出结果如下
2.SUPPORTS
其特点是在事务里面,就事务执行;否则就非事务执行,即
如果存在一个事务,支持当前事务如果没有事务,则非事务的执行使用姿势和前面基本一致
这个传递属性比较特别,所以我们的测试case需要两个,一个事务调用,一个非事务调用测试事务调用时,我们新建一个bean:PropagationDemo2,下面的support方法支持事务运行
对于非事务调用,则是直接在测试类中调用(请注意下面的call方法,调用的是两个不同bean中的support方法)
输出结果如下:
从上面的输出,也可以得出结果:非事务执行时,不会回滚;事务执行时,回滚
3.MANDATORY
需要在一个正常的事务内执行,否则抛异常
使用姿势如下
这种传播属性的特点是这个方法必须在一个已有的事务中运行,所以我们的测试case也比较简单,不再事务中运行时会怎样?
输出结果
从上面的输出可知,直接抛出了异常,并不会执行方法内的逻辑
4.NOT_SUPPORT
这个比较有意思,被它标记的方法,总是非事务地执行,如果存在活动事务,则挂起(实在是没有想到,有什么场景需要这种传播属性)
一个简单的使用case如下:
接下来需要好好的想一下我们的测试用例,首先是它需要在一个事务中调用,外部事物失败回滚,并不会影响上面这个方法的执行结果
我们在PropagationDemo2中,添加测试case如下
输出结果如下
从上面输出可以看出
NOT_SUPPORT标记的方法,属于非事务运行(因为抛异常,修改没有回滚)外部事务回滚,不会影响其修改5.NEVER
总是非事务地执行,如果存在一个活动事务,则抛出异常。
使用姿势如下
我们的测试就比较简单了,如果在事务中运行,是不是会抛异常在PropagationDemo2中,添加一个事务调用方法
测试代码
输出结果
直接抛出了异常,并没有执行方法内的业务逻辑
6.NESTED
其主要特点如下
如果不存在事务,则开启一个事务运行如果存在事务,则运行一个嵌套事务;上面提出了一个嵌套事务的概念,什么是嵌套事务呢?
一个简单的理解:外部事务回滚,内部事务也会被回滚;内部事务回滚,外部无问题,并不会回滚外部事务接下来设计两个测试用例,一个是内部事务回滚;一个是外部事务回滚
a.case1内部事务回滚
在PropagationDemo2这个bean中,添加一个外部事务,捕获上面方法的异常,因此外部执行正常
测试代码
输出结果如下
仔细看一下上面的结果,外部事务修改的结果都被保存了,内部事务的修改被回滚了,没有影响最终的结果
b.case2外部事务回滚
在PropagationDemo2这个bean中,添加一个外部事务,内部事务正常,但是外部事务抛异常,主动回滚
测试代码
输出结果如下
仔细看上面的输出,对别case1,其特别在于全部回滚了,内部事务的修改也被回滚了
7.REQUIRES_NEW
这个和上面的NESTED有点相似,但是又不一样
当存在活动事务时,新创建一个事务执行当不存在活动事务时,和REQUIRES效果一致,创建一个事务执行注意
REQUIRES_NEW和NESTED相比,两个事务之间没有关系,任何一个回滚,对另外一个无影响测试case和前面差不多,不多做细说...
8.小结
前面介绍了7中传播属性,下面简单对比和小结一下