【每日提高之声明式事物】spring声明式事务 同一类内方法调用事务失效
2018-08-01 14:06
344 查看
【问题】
Spring的声明式事务,我想就不用多介绍了吧,一句话“自从用了Spring AOP啊,事务管理真轻松啊,真轻松;事务管理代码没有了,脑不酸了,手不痛了,一口气全配上了事务;轻量级,测试起来也简单,嘿!”。不管从哪个角度看,轻量级声明式事务都是一件解放生产力的大好事。所以,我们“一直用它”。
不过,最近的一个项目里,却碰到了一个事务管理上的问题:有一个服务类,其一个声明了事务的方法,里面做了三次插入SQL操作,但是在后面出错回滚时,却发现前面插入成功了,也是说,这个声明了事务的方法,实际上并没有真正启动事务!怎么回事呢?难道Spring的声明式事务失效了?
【分析】
这个问题,表面上是事务声明失效的问题,实质上很可能是Spring的AOP机制实现角度的问题。我想到很久以前研究Spring的AOP实现时发现的一个现象:对于以Cglib方式增强的AOP目标类,会创建两个对象,一个事Bean实例本身,一个是Cglib增强代理对象,而不仅仅是只有后者。
我们知道,Spring的AOP实现方式有两种:1、Java代理方式;2、Cglib动态增强方式,这两种方式在Spring中是可以无缝自由切换的。Java代理方式的优点是不依赖第三方jar包,缺点是不能代理类,只能代理接口。
Spring通过AopProxy接口,抽象了这两种实现,实现了一致的AOP方式:
现在看来,这种抽象同样带了一个缺陷,那就是抹杀了Cglib能够直接创建普通类的增强子类的能力,Spring相当于把Cglib动态生成的子类,当普通的代理类了,这也是为什么会创建两个对象的原因。下图显示了Spring的AOP代理类的实际调用过程:
因此,从上面的分析可以看出,methodB没有被AopProxy通知到,导致最终结果是:被Spring的AOP增强的类,在同一个类的内部方法调用时,其被调用方法上的增强通知将不起作用。
而这种结果,会造成什么影响呢:
1:内部调用时,被调用方法的事务声明将不起作用
2:换句话说,你在某个方法上声明它需要事务的时候,如果这个类还有其他开发者,你将不能保证这个方法真的会在事务环境中
3:再换句话说,Spring的事务传播策略在内部方法调用时将不起作用。不管你希望某个方法需要单独事务,是RequiresNew,还是要嵌套事务,要Nested,等等,统统不起作用。
4:不仅仅是事务通知,所有你自己利用Spring实现的AOP通知,都会受到同样限制。。。。
【解难】
问题的原因已经找到,其实,我理想中的AOP实现,应该是下面这样:
使用代理
1、Proxy.insertAAA() 代理对象加了事物,这样就可以增强事物。
判断一个Bean是否是AOP代理对象可以使用如下三种方法:
AopUtils.isAopProxy(bean) : 是否是代理对象;
AopUtils.isCglibProxy(bean) : 是否是CGLIB方式的代理对象;
AopUtils.isJdkDynamicProxy(bean) : 是否是JDK动态代理方式的代理对象;
<aop:aspectj-autoproxy expose-proxy="true"/><!—注解风格支持-->
<aop:config expose-proxy="true"><!—xml风格支持-->
修改我们的代码
this.b();-----------修改为--------->((AService) AopContext.currentProxy()).b();
在使用的过程中,提示错误:
@Transactional(propagation = Propagation.REQUIRED,
isolation = Isolation.SERIALIZABLE, rollbackFor = Exception.class)
文章参考:
https://blog.csdn.net/dapinxiaohuo/article/details/52092447 https://blog.csdn.net/aya19880214/article/details/50640596
Spring的声明式事务,我想就不用多介绍了吧,一句话“自从用了Spring AOP啊,事务管理真轻松啊,真轻松;事务管理代码没有了,脑不酸了,手不痛了,一口气全配上了事务;轻量级,测试起来也简单,嘿!”。不管从哪个角度看,轻量级声明式事务都是一件解放生产力的大好事。所以,我们“一直用它”。
不过,最近的一个项目里,却碰到了一个事务管理上的问题:有一个服务类,其一个声明了事务的方法,里面做了三次插入SQL操作,但是在后面出错回滚时,却发现前面插入成功了,也是说,这个声明了事务的方法,实际上并没有真正启动事务!怎么回事呢?难道Spring的声明式事务失效了?
【分析】
这个问题,表面上是事务声明失效的问题,实质上很可能是Spring的AOP机制实现角度的问题。我想到很久以前研究Spring的AOP实现时发现的一个现象:对于以Cglib方式增强的AOP目标类,会创建两个对象,一个事Bean实例本身,一个是Cglib增强代理对象,而不仅仅是只有后者。
我们知道,Spring的AOP实现方式有两种:1、Java代理方式;2、Cglib动态增强方式,这两种方式在Spring中是可以无缝自由切换的。Java代理方式的优点是不依赖第三方jar包,缺点是不能代理类,只能代理接口。
Spring通过AopProxy接口,抽象了这两种实现,实现了一致的AOP方式:
现在看来,这种抽象同样带了一个缺陷,那就是抹杀了Cglib能够直接创建普通类的增强子类的能力,Spring相当于把Cglib动态生成的子类,当普通的代理类了,这也是为什么会创建两个对象的原因。下图显示了Spring的AOP代理类的实际调用过程:
因此,从上面的分析可以看出,methodB没有被AopProxy通知到,导致最终结果是:被Spring的AOP增强的类,在同一个类的内部方法调用时,其被调用方法上的增强通知将不起作用。
而这种结果,会造成什么影响呢:
1:内部调用时,被调用方法的事务声明将不起作用
2:换句话说,你在某个方法上声明它需要事务的时候,如果这个类还有其他开发者,你将不能保证这个方法真的会在事务环境中
3:再换句话说,Spring的事务传播策略在内部方法调用时将不起作用。不管你希望某个方法需要单独事务,是RequiresNew,还是要嵌套事务,要Nested,等等,统统不起作用。
4:不仅仅是事务通知,所有你自己利用Spring实现的AOP通知,都会受到同样限制。。。。
【解难】
问题的原因已经找到,其实,我理想中的AOP实现,应该是下面这样:
使用代理
1、Proxy.insertAAA() 代理对象加了事物,这样就可以增强事物。
public void a() { aopProxy.b();//即调用AOP代理对象的b方法即可执行事务切面进行事务增强 }
判断一个Bean是否是AOP代理对象可以使用如下三种方法:
AopUtils.isAopProxy(bean) : 是否是代理对象;
AopUtils.isCglibProxy(bean) : 是否是CGLIB方式的代理对象;
AopUtils.isJdkDynamicProxy(bean) : 是否是JDK动态代理方式的代理对象;
<aop:aspectj-autoproxy expose-proxy="true"/><!—注解风格支持-->
<aop:config expose-proxy="true"><!—xml风格支持-->
修改我们的代码
this.b();-----------修改为--------->((AService) AopContext.currentProxy()).b();
在使用的过程中,提示错误:
关于AOP无法切入同类调用方法的问题,给方式使用注解
@Transactional(propagation = Propagation.REQUIRED,
isolation = Isolation.SERIALIZABLE, rollbackFor = Exception.class)
文章参考:
https://blog.csdn.net/dapinxiaohuo/article/details/52092447 https://blog.csdn.net/aya19880214/article/details/50640596
相关文章推荐
- spring声明式事务 同一类内方法调用事务失效
- spring声明式事务 同一类内方法调用事务失效
- spring声明式事务 同一类内方法调用事务失效
- spring声明式事务 同一类内方法调用事务失效
- SpringBoot CGLIB AOP解决Spring事务,对象调用自己方法事务失效.
- spring声明式事务 同一类内方法调用事务失效
- spring声明式事务 同一类内方法调用事务失效
- spring 声明式事务、异步调用、AOP灯增强类功能 失效问题
- spring声明式事务 同一类内方法调用事务失效
- spring声明式事务 同一类内方法调用事务失效
- spring声明式事务 同一类内方法调用事务失效
- 使用spring声明式事务,spring使用AOP来支持声明式事务,会根据事务属性,自动在方法调用之前决定是否开启一个事务,并在方法执行之后决定事务提交或回滚事务。
- spring声明式事务 同一类内方法调用事务失效
- spring事物配置,声明式事务管理和基于@Transactional注解的使用
- [spring transaction],service实现类中非事务方法直接调用自身事务方法导致事务无效的原因
- spring事物配置,声明式事务管理和基于@Transactional注解的使用
- spring事物配置,声明式事务管理和基于@Transactional注解的使用
- Spring声明式事务配置管理方法(Spring中的四种声明式事务的配置)
- Spring事务传播特性的浅析——事务方法嵌套调用的迷茫
- spring事物配置,声明式事务管理和基于@Transactional注解的使用