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调用了自己的方法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方式:
现在看来,这种抽象同样带了一个缺陷,那就是抹杀了Cglib能够直接创建普通类的增强子类的能力,Spring相当于把Cglib动态生成的子类,当普通的代理类了,这也是为什么会创建两个对象的原因。下图显示了Spring的AOP代理类的实际调用过程:
因此,从上面的分析可以看出,methodB没有被AopProxy通知到,导致最终结果是:被Spring的AOP增强的类,在同一个类的内部方法调用时,其被调用方法上的增强通知将不起作用。
而这种结果,会造成什么影响呢:
1:内部调用时,被调用方法的事务声明将不起作用
2:换句话说,你在某个方法上声明它需要事务的时候,如果这个类还有其他开发者,你将不能保证这个方法真的会在事务环境中
3:再换句话说,Spring的事务传播策略在内部方法调用时将不起作用。不管你希望某个方法需要单独事务,是RequiresNew,还是要嵌套事务,要Nested,等等,统统不起作用。
4:不仅仅是事务通知,所有你自己利用Spring实现的AOP通知,都会受到同样限制。。。。
[解难]
问题的原因已经找到,其实,我理想中的AOP实现,应该是下面这样:
只要一个Cglib增强对象就好,对于Java代理方式,我的选择是毫不犹豫的抛弃。
至于前面的事务问题,只要避开Spring目前的AOP实现上的限制,要么都声明要事务,要么分开成两个类,要么直接在方法里使用编程式事务,那么一切OK。
相关推荐
描述部分进一步说明了事务失效的后果往往不明显,容易在测试环节被忽略,但在生产环境中出现问题,暴露了开发者对Spring事务机制不足够了解的问题。标签“Spring 事务 失效”直接概括了本文的知识点范围,即Spring...
Spring事务失效Spring事务失效
"Spring事务失效的具体场景及解决方案详细整理" 在实际项目开发中,为了保证业务数据的一致性,大家一般都会采用事务机制。但是,很多小伙伴可能只是简单了解一下,遇到事务失效的情况,便会无从下手。下面我们将...
Spring事务失效问题分析及解决方案 在本文中,我们将详细介绍 Spring 中的事务失效问题分析及解决方案。Spring 事务机制是基于 AOP 实现的,通过使用 @Transaction 注解来标注事务方法。然而,在实际开发中,可能会...
2. **Spring 自定义切面事务失效的原因** - 当我们创建自定义切面并通过`@Aspect`注解将其标记为切面时,如果没有正确地处理事务管理器和切面之间的关系,可能会导致事务失效。 - 默认情况下,Spring 的AOP代理...
Synchronized锁在Spring事务管理下,导致线程不安全。
本资源讲解的是Spring事务的相关技术,需要可自行下载。 课程内容: 1.实战了解学习源码应有的姿势? 2.埋坑,从深坑中玩转事务; 3.迷一般的事务?我数据验证为啥失效? 4.透过源码学习事务隔离级别; 5.源码解读,...
以下是对Spring事务10种常见失效场景的详细分析: 1. **未开启事务**:如果在需要事务控制的方法中忘记添加`@Transactional`注解,Spring将不会自动进行事务管理,导致事务失效。记得在服务层方法上正确使用该注解...
本文将深入探讨Spring事务失效的常见原因,帮助开发者识别并解决这些问题。 首先,我们要明白Spring事务的工作原理。Spring采用AOP(面向切面编程)来实现事务管理,通过动态代理在方法执行前后插入事务处理逻辑。...
然而,在实际开发过程中,经常会遇到一些关于Spring事务的问题,如事务失效、事务回滚、大事务问题以及编程式事务等。本文将深入探讨这些问题,并给出相应的解决方案。 #### 一、事务不生效的原因及解决办法 1. **...
互联网资讯,技术简介,IT、AI技术,人工智能互联网资讯,技术简介,IT、AI技术,人工智能互联网资讯,技术简介,IT、AI技术,人工智能互联网资讯,技术简介,IT、AI技术,人工智能互联网资讯,技术简介,IT、AI技术...
本示例主要讲解如何使用Spring Boot结合MyBatis实现多数据源切换,并确保AOP事务管理仍然有效。 首先,我们需要配置多数据源。在Spring Boot中,可以使用`DataSource`接口的实现类,如`HikariCP`或`Druid`,创建两...
Spring事务管理主要包括编程式事务管理和声明式事务管理两种方式,使得开发者能够在不深入理解底层事务实现的情况下,轻松地在应用程序中管理事务。 1. **编程式事务管理**: 编程式事务管理是通过调用`...
Spring Dynamic Modules(Spring-DM,现在已经被Spring OSGi取代)提供了一种方式来处理这种情况,它可以帮助我们在OSGi环境中创建透明的Spring事务代理。 此外,我们需要确保所有涉及事务的服务都在同一个...
spring事务_案例_PPT 一、事务传播机制的demo案例,内容包括: 1.业务代码列举7种事务传播机制的情况,每个测试方法都附带日志分析记录、使用场景和实际场景,小白也能看得懂!!! 2.在测试类Test包下,使用juniter...
Spring+SpringMVC配置事务管理无效原因及解决办法详解 Spring 框架是 Java 企业级应用程序的核心框架,提供了事务管理机制,以确保业务逻辑的原子性和一致性。然而,在使用 Spring 和 SpringMVC 配置事务管理时,...
- Spring事务管理器会捕获到方法抛出的异常,并根据配置决定是否回滚事务。 4. **事务的边界** - 事务的边界通常由方法定义,事务管理器会在方法调用开始时开始事务,在方法正常结束时提交事务,遇到异常时回滚...
在使用Springboot和shiro集成时,发现部分service的缓存和事务失效,通过debug代码发现这些有问题的service实例都不是代理生成的,导致事务和缓存失效。进一步分析发现,这些有问题的service全部被shiro的realm所...