美文网首页
【每天一道面试题/bug解决】2)Spring事物失效问题

【每天一道面试题/bug解决】2)Spring事物失效问题

作者: 方凌霄 | 来源:发表于2019-05-24 19:54 被阅读0次

    咋么先来看一类

    public class Demo{

        @Transactional

        public void insert() { /* … */ }

        public void query() {

            this.insert();

        }

    }

    可能会有不少人会跟我一样,觉得上面这种方式调用 query()方法时,insert()上的@Transactional注解还是会起作用的,insert()在被调用时,将会开启事务。 但是,当实际操作之后,你会发现,这样并不会开启新的事务?

    为什么呢?

    我们知道,Spring之所以可以对开启@Transactional的方法进行事务管理,是因为Spring为当前类生成了一个代理类,然后在运行相关方法时,会判断这个方法有没有@Transactional注解,如果有的话,则会开启一个事务。 但是,上面这种调用方式时,在调用query()时,使用的并不是代理对象,从而导致this.insert()时也不是代理对象,从而导致@Transactional失败。 其实现原理是 AOP , 而 AOP 的原理是动态代理 , 在自调用的过程中 , 是类自身的调用 ,而不是代理对象去调用, 那么就不会产生 AOP , 这样 Spring就不能把你的代码织入到约定的流程中 , 于是就产生了现在看到的失败场景。

    换句话说,就是在spring得aop中,切面配置的是某个包下的某个方法,整个流程是加载Demo类,调用query()方法,再调用insert()方法,最终返回的是Demo类产生query()的结果,整个过程最终结果是没有事务管控的,所以说insert()方法事务失效!仅限于同一个类下,我觉得可以这样去理解。

    那么,对于这种情况,要怎么处理呢?

    首先,在spring的xml中加上如下配置

    <aop:aspectj-autoproxy expose-proxy="true"/>

    1

    然后,在baz() 中,改成如下方式调用

    public class Demo{

        @Timed

        public void insert() { /* … */ }

        public void query() {

            ((Demo) AopContext.currentProxy()).insert();

        }

    }

    PS: 如果是通过 “@Aspect” 注解实现的 AOP,那么,暂时还没有找到方法来解决

    相关文章

      网友评论

          本文标题:【每天一道面试题/bug解决】2)Spring事物失效问题

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