咱们先来看一个类
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();
}
}