文章目录
  1. 1. 表达式问题
  2. 2. 不在一个容器管理范围
  3. 3. 同一个方法嵌套调用

在以前的项目开发中,经常会听到我这个方法的事务怎么没有起作用呢?虽然经过一番折腾把问题解决了,但是对于spring事务本质的一些东西感觉并没有搞明白。这里就以前项目中遇到的实际问题,再加上自己在一些java群里面看到的问题,对spring事务失效问题做个总结。

以下分析都是基于bean已经在容器中了,有时候事务失效也会因为包没有被扫描到或者xml配置文件没有将bean注册到容器中,这个很少见就不单独说了,下面这些问题就是开发中可能比较常见的问题,这里列出来的也许不全,后期遇到了再补上。

表达式问题

对于xml或者annotation集中式管理事务,常常会配置在pointcut标签或者注解配置一个表达式,save或者update开头的方法加事务,如果项目是按照模块化分包的,就容易出现覆盖不全的情况,从而造成事务失效。

不在一个容器管理范围

这个问题经常发生在于springMVC项目中,在spring源码分析之MVC简介章节分析了,springMVC的web容器是root容器的一个子容器,有的项目会在web.xml将两个容器分别配置,而web容器里面使用context:component-scan标签扫描包将service层的类也给扫到了,就会造成web子容器就有service类了,但是事务的配置又在root容器中,就会造成拿到的bean是web子容器中的bean,并不是一个代理bean,函数调用的时候压根儿就不在事务的拦截器链了,这个问题我相信很多springMVC的项目都会遇到。

同一个方法嵌套调用

这个问题自己在一个项目开发中也遇到过,就是将事务操作失败的日记记录到日志表中,当时就想当然的直接在service方法中增加一个记录日志的方法,事务的传播属性设置为REQUIRES_NEW,结果自测的时候,发现日志表中并没有记录错误日志。如下图所示:

从图中可以看出,如果是目标函数内部的方法调用,是不会走事务拦截过程的,因为事务只是spring aop的一个advice,所以要实现事务的功能,目标函数类必须是一个代理对象,参考spring源码分析之AOP分析。如果要在同一个类中调用方法使事务生效,就要使用<aop:config expose-proxy=”true”>标签,并且将expose-proxy设置为true,内部在执行目标函数的时候,就会把当前的代理类放到AopContext,内部调用的时候就不能直接写方法调用了,要使用AopContext.currentProxy()获取当前的代理类再执行要使用的方法。spring官方文档也说明了这个问题

综上所述,不管以后遇到什么事务失效的问题,首先就应该判断目标函数所在对象是不是一个代理对象,spring有个AopUtils类,不管项目使用jdk proxy还是cglib,或者两种一起用的,使用这个工具类就可以判断是不是代理对象,经过这样的判断可以排除大多数问题。网上还有其他什么自己配置了创建代理对象类,造成二次代理失效的,如果项目中有aop配置,事务创建代理对象的工厂类与aop使用的是同一个类AspectJAwareAdvisorAutoProxyCreator,如果没有特殊需求,还是使用aop:config标签,不然自己配置创建代理对象类,很容易造成拦截器链的丢失,从而造成事务失效。

文章目录
  1. 1. 表达式问题
  2. 2. 不在一个容器管理范围
  3. 3. 同一个方法嵌套调用