前言:轮到我了哈哈,最近在测接口的时候发现@Transactional标记的方法事务没有生效,问了同事是说与动态代理有关,于是我复习了一下,顺便做个记录
问题重现
如果你已经完全理解动态代理,那么我讲一句话你应该就明白为什么失效了(可以跳过此部分)
即:在方法内部自己调用方法
public class XxxxServiceImpl extends ServiceImpl<XxxxMapper, Xxxx> implements XxxxService{
@Override
@Transactional
public void funcA(){
// 代码略
}
@Override
@Transactional
public void funcB(){
this.funcA() // 问题代码
}
}
上述代码中,在调用XxxxService.funcB()时,内部的funcA()方法的事务会失效。
同理,如果将@Transactional换成自定义的注解,然后使用自定义的切面去扫描,打断点测试只会扫描到funcB(),而同样有注解的funcA()则不会触发断点。
如何修复
其实只要复习一下动态代理的过程就能明白,无论是spring实现的事务还是自己实现基于注解的切面逻辑,都是通过代理对象调用方法来实现对方法的增强
所以目标很明确了,我们在类内部调用自己的方法时,如果需要触发动态代理的增强逻辑,则应该通过代理对象调用自己内部的方法
如何获取当前对象的代理对象?
AopContext.currentProxy()// 这行代码就可以获取当前对象的代理对象
所以修改后如下,此时两个事务都能触发
public class XxxxServiceImpl extends ServiceImpl<XxxxMapper, Xxxx> implements XxxxService{
@Override
@Transactional
public void funcA(){
// 代码略
}
@Override
@Transactional
public void funcB(){
// 通过代理对象调用内部方法
XxxxServiceImpl proxy = (XxxxServiceImpl) AopContext.currentProxy()
proxy.funcA()
}
}
别忘记去启动类开启暴露代理对象
@EnableAspectJAutoProxy(exposeProxy=true,proxyTargetClass=true)
@SpringBootApplication
@EnableTransactionManagement
@EnableAspectJAutoProxy(exposeProxy=true,proxyTargetClass=true) // 添加这行代码
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}