service
image
模拟动态代理事务
image
测试类
image
预测结果
模拟事务:开启事务
execute doLink
模拟事务:关闭事务
模拟事务:开启事务
execute doPick
模拟事务:关闭事务
execute unDo
实际结果
模拟事务:开启事务
execute doLink
模拟事务:关闭事务
模拟事务:开启事务
execute doPick
模拟事务:关闭事务
execute unDo
结果一致,运行正常
我们修改service和测试类
修改后的service(在事务方法中调用事务方法,在非事务方法中调用事务方法)
图片.png
修改后的测试类
image
预测结果
模拟事务:开启事务
execute doLink
模拟事务:开启事务
execute doPick
模拟事务:关闭事务
模拟事务:关闭事务
execute unDo
模拟事务:开启事务
execute doPick
模拟事务:关闭事务
测试结果
模拟事务:开启事务
execute doLink
execute doPick
模拟事务:关闭事务
execute unDo
execute doPick
结果不一致,doLink方法里调用doPick没有触发事务,unDo方法里调用doPick也没有触发事务
分析问题的本质
我们知道Spring事务管理是通过JDK动态代理的方式进行实现的(另一种是使用CGLib动态代理实现的),也正是因为动态代理的特性造成了上述doLink方法调用doPick方法的时候造成了doPick方法中的事务失效!简单的来说就是doLink方法调用doPick方法的时候doPick方法的事务是不起作用的,此时的doPick方法像一个没有加事务的普通方法。那么动态代理的这个特性到底是什么才会造成Spring事务失效?这是因为在Java中doLink方法中调用doPick方法,本质上就相当于把doPick方法的方法体放入到doLink方法中,也就是内部方法,同样的不管你嵌套了多少层,只有调用代理对象的方法才会触发事务。
如何解决这个坑
1.使用代理对象去调用方法
2.再加一层XXXService分别去调用doLink方法和doPick方法(没修改前的代码在控制器层分别调用doLink方法和doPick方法)
针对方案一对代码改版
修改后的service
image
修改后的测试类
image
预测结果
模拟事务:开启事务
execute doLink
模拟事务:开启事务
execute doPick
模拟事务:关闭事务
模拟事务:关闭事务
execute unDo
模拟事务:开启事务
execute doPick
模拟事务:关闭事务
测试结果
模拟事务:开启事务
execute doLink
模拟事务:开启事务
execute doPick
模拟事务:关闭事务
模拟事务:关闭事务
execute unDo
模拟事务:开启事务
execute doPick
模拟事务:关闭事务
结果一致,解决问题
网友评论