一 结论
先说结论再看效果
1、在同一个类中,一个无事务方法调用另一个有事务注解方法(@Transational)的方法,注解事务是不会生效的
2、在同一个类中,一个有事务方法调用另一个有事务注解方法(@Transational)的方法,只有外层事务有效,被调的注解事务是不会生效的
3、在不同类中,一个有事务方法调用另一个有事务注解方法(@Transational)的方法,两个方法都有事务
4、在不同类中,一个无事务方法调用另一个有事务注解方法(@Transational)的方法,有注解事务是生效的
二 测试
咱们的测试均采用默认的传播机制!!!
首先我们先看第一种情况的测试数据
code
预期
预期效果就是会新增一条数据,id为46、47的name值均被修改。提示一下大家在测试的时候,如果注释掉@Transational注解一定要重启项目!一定要重启项目!一定要重启项目! 因为spring采用的是aop动态代理,它会动态的去创建代理类,不要想着偷懒用jrebel去做测试!
实际效果
好了,我们一起看下实际效果(截图上的备注可以忽略掉)
果然,跟我们的预期效果一致
接下来我们针对第二种情况进行测试,首先我们先看下测试数据
code
现在save()、update()都有添加了@Transational事务注解
预期
根据结论update()方法事务不会生效,那么也就是说update()方法中的修改是不会被回滚的
实际效果
意不意外,惊不惊喜,数据并没有发生改变!!!这可能会有人会觉得只要在本类方法中都加上@Transational注解就不存在事务会失效,那么恭喜你进入大坑了。在同一个类中一个有事务方法调用另一个有事务注解方法(@Transational)的方法,只有外层事务有效,也就是说update()方法抛出了异常被save()方法感知到了,这才导致事务回滚,如果我这样说不能理解的话,看接下来的测试或许你会茅塞顿开。
接下来我要让你明白啥叫事务的厉害!!!我把update()用 try{}catch{}住,如果update()方法有事务的话,save()方法操作的数据就不会新增。
控制台输出
异常被吃掉了,所以没有异常日志
看到没 update()方法中的修改没有被回滚,由于save()方法中catch块没有抛出异常所以数据也会新增。但是有的同学可能会问,你都try{}catch{}为什么不手动抛异常让外层感知到然后把自己的操作回滚掉。你或许可以换个角度想一下,如果update有事务的话本方法内一旦报错那么数据是一定要回滚的,而现在就是报错了但没有回滚掉,就因为catch掉了?
接下来我们针对第三种情况进行测试,首先我们先看下测试数据
code
在不同类中,一个有事务方法调用另一个有事务注解方法(@Transational)的方法
预期
数据不会发生改变
实际情况
同样还是报错了,我们再看看数据库中的数据
很好,没有发生改变,接下来我们同样用try{}catch{}的方式测试一下
我们再看看效果
看到没,这才叫有事务!!!
多层嵌套事务中,如果使用了默认的事务传播方式,当内层事务抛出异常,外层事务捕捉并正常执行完毕时,就会报出rollback-only异常。
spring框架是使用AOP的方式来管理事务,如果一个被事务管理的方法正常执行完毕,方法结束时spring会将方法中的sql进行提交。如果方法执行过程中出现异常,则回滚。spring框架的默认事务传播方式是PROPAGATION_REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。
在项目中,一般我们都会使用默认的传播方式,这样无论外层事务和内层事务任何一个出现异常,那么所有的sql都不会执行。在嵌套事务场景中,内层事务的sql和外层事务的sql会在外层事务结束时进行提交或回滚。如果内层事务抛出异常e,在内层事务结束时,spring会把事务标记为“rollback-only”。这时如果外层事务捕捉了异常e,那么外层事务方法还会继续执行代码,直到外层事务也结束时,spring发现事务已经被标记为“rollback-only”,但方法却正常执行完毕了,这时spring就会抛出“org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only”。
再看看数据库中的数据
没有发生任何变化
接下来我们针对第四种情况进行测试,首先我们先看下测试数据
直接上code
code
这次我把save()方法注解去掉,直接看结果吧!
没有出现Transaction rolled back because it has been marked as rollback-only异常了,因为外层没有事务,我们看下数据库中的数据
id为48的name没有被修改,也就是说事务生效了!!!
现在是北京时间2021年05月14日00:05:11
累了,今天的使用心得就到此结束了,希望对你的工作学习有所帮助
2021年05月16日13:06:44 更新一下 现在有这么一个场景,如果本类中一个有事务A方法调用另一个有事务注解方法(@Transational)的B方法,然后B方法再调用其它service有事务的C方法,会发生什么情况呢? 先看一下代码
结果就是B方法中操作的数据也会提交,并不会回滚!!!
如果说C方法抛出异常会怎么样呢?答案是都会回滚!!!
因为它加入了A方法中的事务,所以C方法报错会让A方法对事务进行回滚!!!