美文网首页
JDK动态代理给Spring事务埋下的坑

JDK动态代理给Spring事务埋下的坑

作者: TheLights | 来源:发表于2018-03-16 11:09 被阅读314次

    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
    模拟事务:关闭事务

    结果一致,解决问题

    相关文章

      网友评论

          本文标题:JDK动态代理给Spring事务埋下的坑

          本文链接:https://www.haomeiwen.com/subject/qcslqftx.html