spring声明式事务 同一类内方法调用事务失效

时间:2022-08-27 16:50:25

只要避开Spring目前的AOP实现上的限制,要么都声明要事务,要么分开成两个类,要么直接在方法里使用编程式事务

[问题]

Spring的声明式事务,我想就不用多介绍了吧,一句话“自从用了Spring AOP啊,事务管理真轻松啊,真轻松;事务管理代码没有了,脑不酸了,手不痛了,一口气全配上了事务;轻量级,测试起来也简单,嘿!”。不管从哪个角度看,轻量级声明式事务都是一件解放生产力的大好事。所以,我们“一直用它”。

不过,最近的一个项目里,却碰到了一个事务管理上的问题:有一个服务类,其一个声明了事务的方法,里面做了三次插入SQL操作,但是在后面出错回滚时,却发现前面插入成功了,也是说,这个声明了事务的方法,实际上并没有真正启动事务!怎么回事呢?难道Spring的声明式事务失效了?

[探幽]

其实以前也会碰到有人说,Spring的事务配置不起作用,但是根据第一反应和以往经验,我总会告诉他,肯定是你的配置有问题啦;所以这一次,我想也不会例外,大概是把事务注解配在了接口上而不是实现方法上,或者,如果是用XML声明方式的话,很可能是切入点的表达式没有配对。

不过,在检查了他们的配置后,却发现没有配置问题,该起事务的实现方法上,用了@Transactional事务注解声明,XML里也配了注解驱动<tx:annotation-driven .../>,配置很正确啊,怎么会不起作用?

我很纳闷,于是往下问:

问1:其他方法有这种情况么?

答1:没有。

问2:这个方法有什么特别的么(以下简称方法B)?

答2:就是调后台插了三条记录啊,没啥特别的。

问3:这个方法是从Web层直接调用的吧?

答3:不是,是这个Service类(以下简称ServiceA)的另外一个方法调过来的(以下简称方法A)。

问4:哦,那个调用它的方法配了事务么(问题可能在这了)?

答4:没有。

问5:那WEB层的Action(用的是Struts2),调用的是没有声明事务的方法A,方法A再调用声明了事务的方法B?

答5:对的。

问6:你直接在方法A上加上事务声明看看

答6:好。。。

看来可能找到问题所在了,于是把@Transactional也加在方法A上,启动项目测试,结果是:事务正常生效,方法A和方法B都在一个事务里了。

好了,现在总结一下现象:

1、ServiceA类为Web层的Action服务

2、Action调用了ServiceA的方法A,而方法A没有声明事务(原因是方法A本身比较耗时而又不需要事务)

3、ServiceA的方法A调用了自己所在class的方法B,而方法B声明了事务,但是方法B的事务声明在这种情况失效了。

4、如果在方法A上也声明事务,则在Action调用方法A时,事务生效,而方法B则自动参与了这个事务。

我让他先把A也加上事务声明,决定回来自己再测一下。

这个问题,表面上是事务声明失效的问题,实质上很可能是Spring的AOP机制实现角度的问题。
我想到很久以前研究Spring的AOP实现时发现的一个现象:对于以Cglib方式增强的AOP目标类,会创建两个对象,一个事Bean实例本身,一个是Cglib增强代理对象,而不仅仅是只有后者。我曾经疑惑过这一点,但当时没有再仔细探究下去。

我们知道,Spring的AOP实现方式有两种:1、Java代理方式;2、Cglib动态增强方式,这两种方式在Spring中是可以无缝*切换的。
Java代理方式的优点是不依赖第三方jar包,缺点是不能代理类,只能代理接口

Spring通过AopProxy接口,抽象了这两种实现,实现了一致的AOP方式:

spring声明式事务 同一类内方法调用事务失效

现在看来,这种抽象同样带了一个缺陷,那就是抹杀了Cglib能够直接创建普通类的增强子类的能力,Spring相当于把Cglib动态生成的子类,当普通的代理类了,这也是为什么会创建两个对象的原因。下图显示了Spring的AOP代理类的实际调用过程:

spring声明式事务 同一类内方法调用事务失效

因此,从上面的分析可以看出,methodB没有被AopProxy通知到
导致最终结果是:
被Spring的AOP增强的类,在同一个类的内部方法调用时,其被调用方法上的增强通知将不起作用。

而这种结果,会造成什么影响呢:

1:内部调用时,被调用方法的事务声明将不起作用

2:换句话说,你在某个方法上声明它需要事务的时候,如果这个类还有其他开发者,你将不能保证这个方法真的会在事务环境中

3:再换句话说,Spring的事务传播策略内部方法调用时将不起作用。
不管你希望某个方法需要单独事务,是RequiresNew,还是要嵌套事务,要Nested,等等,统统不起作用。

4:不仅仅是事务通知,所有你自己利用Spring实现的AOP通知,都会受到同样限制。。。。

[解难]

问题的原因已经找到,其实,我理想中的AOP实现,应该是下面这样:

spring声明式事务 同一类内方法调用事务失效

只要一个Cglib增强对象就好,对于Java代理方式,我的选择是毫不犹豫的抛弃。

至于前面的事务问题,只要避开Spring目前的AOP实现上的限制,要么都声明要事务,要么分开成两个类,要么直接在方法里使用编程式事务,那么一切OK。

原文地址:http://blog.csdn.net/seelye/article/details/40144817

http://blog.csdn.net/aya19880214/article/details/50640596

spring声明式事务 同一类内方法调用事务失效的更多相关文章

  1. spring声明式事务 同一类内方法调用事务失效&lpar;转&rpar;

    原文 https://blog.csdn.net/jiesa/article/details/53438342 [问题] Spring的声明式事务,我想就不用多介绍了吧,一句话“自从用了Spring ...

  2. Spring声明式事务配置管理方法

    环境配置 项目使用SSH架构,现在要添加Spring事务管理功能,针对当前环境,只需要添加Spring 2.0 AOP类库即可.添加方法: 点击项目右键->Build Path->Add ...

  3. Spring声明式事务配置管理方法(转)

    项目使用SSH架构,现在要添加Spring事务管理功能,针对当前环境,只需要添加Spring 2.0 AOP类库即可.添加方法: 点击项目右键->Build Path->Add libra ...

  4. 使用spring声明式事务,spring使用AOP来支持声明式事务,会根据事务属性,自动在方法调用之前决定是否开启一个事务,并在方法执行之后决定事务提交或回滚事务。

    使用spring声明式事务,spring使用AOP来支持声明式事务,会根据事务属性,自动在方法调用之前决定是否开启一个事务,并在方法执行之后决定事务提交或回滚事务.

  5. spring声明式事务管理总结

    事务配置 首先在/WEB-INF/applicationContext.xml添加以下内容: <!-- 配置事务管理器 --> <bean id="transactionM ...

  6. Spring声明式事务管理基于&commat;Transactional注解

    概述:我们已知道Spring声明式事务管理有两种常用的方式,一种是基于tx/aop命名空间的xml配置文件,另一种则是基于@Transactional 注解.         第一种方式我已在上文为大 ...

  7. Spring声明式事务管理与配置详解

    转载:http://www.cnblogs.com/hellojava/archive/2012/11/21/2780694.html 1.Spring声明式事务配置的五种方式 前段时间对Spring ...

  8. Spring声明式事务的配置~~~

    /*2011年8月28日 10:03:30 by Rush  */ 环境配置 项目使用SSH架构,现在要添加Spring事务管理功能,针对当前环境,只需要添加Spring 2.0 AOP类库即可.添加 ...

  9. 【spring基础】spring声明式事务详解

    一.spring声明式事务 1.1 spring的事务管理器 spring没有直接管理事务,而是将管理事务的责任委托给JTA或相应的持久性机制所提供的某个特定平台的事务实现.spring容器负责事物的 ...

随机推荐

  1. logback配置详解3&lt&semi;filter&gt&semi;

    logback 常用配置详解(三) <filter> <filter>: 过滤器,执行一个过滤器会有返回个枚举值,即DENY,NEUTRAL,ACCEPT其中之一.返回DENY ...

  2. iOS:个人浅谈工厂模式

    一.什么是工厂方法? 正式的解释是:在基类中定义创建对象的一个接口,让子类决定实例化哪个类.工厂方法让一个类的实例化延迟到子类中进行.工厂方法要解决的问题是对象的创建时机,它提供了一种扩展的策略,很好 ...

  3. shell学习记录002-知识点储备

    1.echo "4*0.33" |bc    #计算机功能的运用 [root@oc3408554812 shell]# ss=22; [root@oc3408554812 shel ...

  4. svn IP地址变更后如何变更

    通过grep ip地址,发现svn中url地址信息是记录在.svn文件夹entries文件中的,第一种方案应该是遍历目录下的entries文件,将ip替换为新的ip即可. 可以发现这个用sed命令即可 ...

  5. 2&period;redis&period;3&period;2 下载,安装、配置、使用 - 2

    上篇简单介绍了 下载,安装,测试,现在直接使用了,看结果 使用的redis服务便是,上篇临时搭建的简易服务,,注意,说的是简易,因为它只是一个单点的“玩具”: 临时在项目登录的时候模拟了一下,这里使用 ...

  6. ●BZOJ 2251 &lbrack;2010Beijing Wc&rsqb;外星联络

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=2251 题解: 后缀数组,倍增,RMQ 题意:把重复次数超过 1次的子串按字典序输出它们重复的 ...

  7. DNS区域传送漏洞实验以及二级域名爆破

    DNS区域传送漏洞实验以及二级域名爆破 目录: 1.DNS服务器的域传送漏洞(nslookup交互式.非交互式.批处理三种方式) 2.写个二级域名爆破脚本 一.DNS服务器的域传送漏洞 实验环境: 服 ...

  8. ElasicSearch&lpar;2&rpar; Linux运行

    1.org.elasticsearch.bootstrap.StartupException: java.lang.RuntimeException: can not run elasticsearc ...

  9. php上传导入文件 nginx-502错误

    4. php程序执行时间过长而超时,检查nginx和fastcgi中各种timeout设置.(nginx 中的  fastcgi_connect_timeout 300;fastcgi_send_ti ...

  10. 【php】页面加载优化的14条原则

      1. 尽可能的减少 HTTP 的请求数 [content] 2. 使用 CDN(Content Delivery Network) [server] 3. 添加 Expires 头(或者 Cach ...