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

咋么先来看一类

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,那么,暂时还没有找到方法来解决

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容