- 浏览: 1527074 次
- 性别:
- 来自: 厦门
博客专栏
-
Spring 3.x企业实...
浏览量:464137
文章分类
最新评论
-
JyeChou:
学习Spring必学的Java基础知识(1)----反射 -
hhzhaoheng:
...
《Spring4.x企业应用开发实战》光盘资料下载 -
renlongnian:
//assertReflectionEquals(user1, ...
单元测试系列之3:测试整合之王Unitils -
骑着蜗牛超F1:
huang_yong 写道我的经验是,只需定义三层:1.ent ...
Spring的事务管理难点剖析(2):应用分层的迷惑 -
wangyudong:
工具地址貌似更新了哦https://github.com/Wi ...
几种常用的REST webservice客户端测试工具
哪些方法不能实施Spring AOP事务
由于Spring事务管理是基于接口代理或动态字节码技术,通过AOP实施事务增强的。虽然Spring还支持AspectJ LTW在类加载期实施增强,但这种方法很少使用,所以我们不予关注。
对于基于接口动态代理的AOP事务增强来说,由于接口的方法都必然是public的,这就要求实现类的实现方法也必须是public的(不能是protected、private等),同时不能使用static的修饰符。所以,可以实施接口动态代理的方法只能是使用“public”或“public final”修饰符的方法,其他方法不可能被动态代理,相应的也就不能实施AOP增强,换句话说,即不能进行Spring事务增强了。
基于CGLib字节码动态代理的方案是通过扩展被增强类,动态创建其子类的方式进行AOP增强植入的。由于使用final、static、private修饰符的方法都不能被子类覆盖,相应的,这些方法将无法实施AOP增强。所以方法签名必须特别注意这些修饰符的使用,以免使方法不小心成为事务管理的漏网之鱼。
事务增强遗漏实例
本节中,我们通过具体的实例说明基于CGLib字节码动态代理无法享受Spring AOP事务增强的特殊方法。
Spring通过CGLib动态代理技术对UserService Bean实施AOP事务增强的关键配置,具体如下所示:
在①处,我们通过proxy-target-class="true"显式使用CGLib动态代理技术,在②处通过AspjectJ切点表达式表达UserService所有的方法,希望对UserService所有方法都实施Spring AOP事务增强。
在UserService添加一个可执行的方法,如下所示:
在运行UserService之前,将Log4J日志级别设置为DEBUG,运行以上代码查看输出日志,如下所示:
①未启用事务
before method1
in method1
after method1
②未启用事务
before method2
in method2
after method2
③未启用事务
before method3
in method3
after method3
④启用事务
before method4
Creating new transaction with name [com.baobaotao.special.UserService.method4]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
…
in method4
Initiating transaction commit
Committing JDBC transaction on Connection [jdbc:mysql://localhost:3306/sampledb, UserName=root@localhost, MySQL-AB JDBC Driver]
Releasing JDBC Connection [jdbc:mysql://localhost:3306/sampledb, UserName=root@localhost, MySQL-AB JDBC Driver] after transaction
Returning JDBC Connection to DataSource
after method4
⑤未用事务
before method5
in method5
after method5
⑥启用事务
before method6
Creating new transaction with name [com.baobaotao.special.UserService.method6]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
…
in method6
Initiating transaction commit
Committing JDBC transaction on Connection [jdbc:mysql://localhost:3306/sampledb, UserName=root@localhost, MySQL-AB JDBC Driver]
…
after method6
观察以上输出日志,很容易发现method1~method3及method5这4个方法都没有被实施Spring的事务增强,而method4和method6被实施了事务增强。这个结果验证了我们前面的论述。
我们通过下表描述哪些特殊方法将成为Spring AOP事务增强的漏网之鱼。
不过,需要特别指出的是,这些不能被Spring事务增强的特殊方法并非就不工作在事务环境下。只要它们被外层的事务方法调用了,由于Spring事务管理的传播级别,内部方法也可以工作在外部方法所启动的事务上下文中。我们说,这些方法不能被Spring进行AOP事务增强,是指这些方法不能启动事务,但是外层方法的事务上下文依旧可以顺利地传播到这些方法中。
这些不能被Spring事务增强的方法和可被Spring事务增强的方法唯一的区别在于“是否可以主动启动一个新事务”:前者不能而后者可以。对于事务传播行为来说,二者是完全相同的,前者也和后者一样不会造成数据连接的泄漏问题。换句话说,如果这些“特殊方法”被无事务上下文的方法调用,则它们就工作在无事务上下文中;反之,如果被具有事务上下文的方法调用,则它们就工作在事务上下文中。
对于private的方法,由于最终都会被public方法封装后再开放给外部调用,而public方法是可以被事务增强的,所以基本上没有什么问题。在实际开发中,最容易造成隐患的是基于CGLib的动态代理时的“public static”和“public final”这两种特殊方法。原因是它们本身是public的,因此可以直接被外部类(如Web层的Controller类)调用,只要调用者没有事务上下文,这些特殊方法也就以无事务的方式运作。
注:以上内容摘自《Spring 4.x企业应用开发实战》
由于Spring事务管理是基于接口代理或动态字节码技术,通过AOP实施事务增强的。虽然Spring还支持AspectJ LTW在类加载期实施增强,但这种方法很少使用,所以我们不予关注。
对于基于接口动态代理的AOP事务增强来说,由于接口的方法都必然是public的,这就要求实现类的实现方法也必须是public的(不能是protected、private等),同时不能使用static的修饰符。所以,可以实施接口动态代理的方法只能是使用“public”或“public final”修饰符的方法,其他方法不可能被动态代理,相应的也就不能实施AOP增强,换句话说,即不能进行Spring事务增强了。
基于CGLib字节码动态代理的方案是通过扩展被增强类,动态创建其子类的方式进行AOP增强植入的。由于使用final、static、private修饰符的方法都不能被子类覆盖,相应的,这些方法将无法实施AOP增强。所以方法签名必须特别注意这些修饰符的使用,以免使方法不小心成为事务管理的漏网之鱼。
事务增强遗漏实例
本节中,我们通过具体的实例说明基于CGLib字节码动态代理无法享受Spring AOP事务增强的特殊方法。
package com.baobaotao.special; import org.springframework.stereotype.Service; @Service("userService") public class UserService { //① private方法因访问权限的限制,无法被子类覆盖 private void method1() { System.out.println("method1"); } //② final方法无法被子类覆盖 public final void method2() { System.out.println("method2"); } //③ static是类级别的方法,无法被子类覆盖 public static void method3() { System.out.println("method3"); } //④ public方法可以被子类覆盖,因此可以被动态字节码增强 public void method4() { System.out.println("method4"); } }
Spring通过CGLib动态代理技术对UserService Bean实施AOP事务增强的关键配置,具体如下所示:
… <aop:config proxy-target-class="true"><!-- ①显式使用CGLib动态代理 --> <!-- ②希望对UserService所有方法实施事务增强 --> <aop:pointcut id="serviceJdbcMethod" expression="execution(* com.baobaotao.special.UserService.*(..))"/> <aop:advisor pointcut-ref="serviceJdbcMethod" advice-ref="jdbcAdvice" order="0"/> </aop:config> <tx:advice id="jdbcAdvice" transaction-manager="jdbcManager"> <tx:attributes> <tx:method name="*"/> </tx:attributes> </tx:advice> …
在①处,我们通过proxy-target-class="true"显式使用CGLib动态代理技术,在②处通过AspjectJ切点表达式表达UserService所有的方法,希望对UserService所有方法都实施Spring AOP事务增强。
在UserService添加一个可执行的方法,如下所示:
package com.baobaotao.special; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.stereotype.Service; @Service("userService") public class UserService { … public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("user/special/applicationContext.xml"); UserService service = (UserService) ctx.getBean("userService"); System.out.println("before method1"); service.method1(); System.out.println("after method1"); System.out.println("before method2"); service.method2(); System.out.println("after method2"); System.out.println("before method3"); service.method3(); System.out.println("after method3"); System.out.println("before method4"); service.method4(); System.out.println("after method4"); } }
在运行UserService之前,将Log4J日志级别设置为DEBUG,运行以上代码查看输出日志,如下所示:
引用
①未启用事务
before method1
in method1
after method1
②未启用事务
before method2
in method2
after method2
③未启用事务
before method3
in method3
after method3
④启用事务
before method4
Creating new transaction with name [com.baobaotao.special.UserService.method4]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
…
in method4
Initiating transaction commit
Committing JDBC transaction on Connection [jdbc:mysql://localhost:3306/sampledb, UserName=root@localhost, MySQL-AB JDBC Driver]
Releasing JDBC Connection [jdbc:mysql://localhost:3306/sampledb, UserName=root@localhost, MySQL-AB JDBC Driver] after transaction
Returning JDBC Connection to DataSource
after method4
⑤未用事务
before method5
in method5
after method5
⑥启用事务
before method6
Creating new transaction with name [com.baobaotao.special.UserService.method6]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
…
in method6
Initiating transaction commit
Committing JDBC transaction on Connection [jdbc:mysql://localhost:3306/sampledb, UserName=root@localhost, MySQL-AB JDBC Driver]
…
after method6
观察以上输出日志,很容易发现method1~method3及method5这4个方法都没有被实施Spring的事务增强,而method4和method6被实施了事务增强。这个结果验证了我们前面的论述。
我们通过下表描述哪些特殊方法将成为Spring AOP事务增强的漏网之鱼。
序 号 | 动态代理策略 | 不能被事务增强的方法 |
1 | 基于接口的动态代理 | 除public外的其他所有的方法,此外public static也不能被增强 |
2 | 基于CGLib的动态代理 | private、static、final的方法 |
不过,需要特别指出的是,这些不能被Spring事务增强的特殊方法并非就不工作在事务环境下。只要它们被外层的事务方法调用了,由于Spring事务管理的传播级别,内部方法也可以工作在外部方法所启动的事务上下文中。我们说,这些方法不能被Spring进行AOP事务增强,是指这些方法不能启动事务,但是外层方法的事务上下文依旧可以顺利地传播到这些方法中。
这些不能被Spring事务增强的方法和可被Spring事务增强的方法唯一的区别在于“是否可以主动启动一个新事务”:前者不能而后者可以。对于事务传播行为来说,二者是完全相同的,前者也和后者一样不会造成数据连接的泄漏问题。换句话说,如果这些“特殊方法”被无事务上下文的方法调用,则它们就工作在无事务上下文中;反之,如果被具有事务上下文的方法调用,则它们就工作在事务上下文中。
对于private的方法,由于最终都会被public方法封装后再开放给外部调用,而public方法是可以被事务增强的,所以基本上没有什么问题。在实际开发中,最容易造成隐患的是基于CGLib的动态代理时的“public static”和“public final”这两种特殊方法。原因是它们本身是public的,因此可以直接被外部类(如Web层的Controller类)调用,只要调用者没有事务上下文,这些特殊方法也就以无事务的方式运作。
注:以上内容摘自《Spring 4.x企业应用开发实战》
评论
1 楼
huang_yong
2012-04-14
public方法可以开启一个事务(除去static与final的pulich方法以外),并通过“事务传播机制”传播到到private方法中,所以我们不需要担心private方法就没有事务控制了。
从另外一方面讲,private方法也只能被其它方法调用,它自身也没必要启动事务的。
所以在编程的时候,需要理解“事务传播机制”,防止意外发生!
感谢作者的分享!
从另外一方面讲,private方法也只能被其它方法调用,它自身也没必要启动事务的。
所以在编程的时候,需要理解“事务传播机制”,防止意外发生!
感谢作者的分享!
发表评论
-
一个常见的Spring IOC疑难症状
2013-07-25 14:14 5059Case 请看下面的IOC实例: 1)Aa ... -
mybatis3.1分页自动添加总数
2013-07-08 21:11 22835问题 1.mybatis默认分页是内存分页的,谁用谁崩溃啊! ... -
Rop开发手册(1):最简单的服务开放平台框架
2012-08-08 11:35 8616Rop概述 Rop是Rapid Open Pl ... -
学习Spring必学的Java基础知识(9)----HTTP请求报文
2012-06-09 16:02 13939引述要学习Spring框架的技术内幕,必须事先掌握一些基本的J ... -
学习Spring必学的Java基础知识(8)----国际化信息
2012-05-26 11:19 28460引述要学习Spring框架的 ... -
学习Spring必学的Java基础知识(7)----事务基础知识
2012-05-26 10:57 5089引述要学习Spring框架的技术内幕,必须事先掌握一些基本的J ... -
学习Spring必学的Java基础知识(6)----ThreadLocal
2012-05-19 10:09 12136引述要学习Spring框架的 ... -
学习Spring必学的Java基础知识(5)----注解
2012-05-19 09:56 5776引述要学习Spring框架的技术内幕,必须事先掌握一些基本的J ... -
学习Spring必学的Java基础知识(4)----XML基础知识
2012-05-12 15:33 8559引述要学习Spring框架的 ... -
学习Spring必学的Java基础知识(3)----PropertyEditor
2012-05-12 15:13 16845引述要学习Spring框架的 ... -
明明白白AOP(傻瓜也会心领神会!)
2012-05-05 11:04 10584引子: AOP(面向方面编 ... -
学习Spring必学的Java基础知识(2)----动态代理
2012-05-02 13:03 9710引述要学习Spring框架的 ... -
学习Spring必学的Java基础知识(1)----反射
2012-04-25 13:57 89786引述要学习Spring框架的技术内幕,必须事先掌握一些基本的J ... -
透透彻彻IoC(你没有理由不懂!)
2012-04-18 11:01 94210引述:IoC(控制反转:I ... -
单元测试系列之5:使用unitils测试Service层
2012-04-14 10:48 18443引述:Spring 的测试框架为我们提供一个强大的测试环境,解 ... -
如何用Spring读取JAR中的文件
2012-04-13 17:22 18397使用如下方式读取JAR中的文件出错 类路径下 ... -
单元测试系列之4:使用Unitils测试DAO层
2012-04-12 16:32 19683Spring 的测试框架为我们提供一个强大的测试环境,解 ... -
单元测试系列之3:测试整合之王Unitils
2012-04-09 14:11 15655引述:程序测试对保障应用程序正确性而言,其重要性怎么样强调都不 ... -
单元测试系列之2:模拟利器Mockito
2012-03-30 11:38 15302引述:程序测试对 ... -
单元测试系列之1:开发测试的那些事儿
2012-03-28 12:52 10013引述:程序测试对保障应用程序正确性而言,其重要性怎 ...
相关推荐
在Spring框架中,事务管理是核心特性之一,它允许开发者以声明式或编程式的方式处理应用中的事务。Spring事务管理的目的是确保数据的一致性和完整性,尤其是在多操作、多资源的环境中。本Demo将深入探讨Spring如何...
编程式事务管理通过TransactionTemplate或直接调用PlatformTransactionManager接口的方法来管理事务,而声明式事务管理则通过在配置文件或注解中定义事务规则,让Spring自动处理事务开始、提交、回滚等操作。...
本篇文章将深入探讨Spring事务管理的五种方法,旨在帮助开发者更好地理解和运用这一核心特性。 首先,我们来了解什么是事务。在数据库操作中,事务是一组逻辑操作,这些操作要么全部成功,要么全部失败,确保数据的...
1. **Spring声明式事务管理**:这是Spring中最常用的一种事务管理方式,通过在方法上添加@Transactional注解,Spring容器会在方法执行前后自动进行事务的开启、提交、回滚等操作。例如,在业务服务类的方法上标注此...
在Spring框架中,事务管理是核心特性之一,用于确保数据操作的一致性和完整性。当一个方法(A方法)内部调用另一个方法(B方法)时,可能会遇到事务控制的复杂情况。本示例代码旨在解决在A方法内部调用B方法时的回滚...
### Spring事务管理详解 #### 一、Spring事务管理概述 Spring框架提供了强大的事务管理功能,使得开发者能够更方便地管理应用程序中的事务。Spring事务管理主要包括两种类型:编程式事务管理和声明式事务管理。 -...
同时,Spring还提供了编程式事务管理,允许开发者在代码中手动管理事务,但这种方式通常在更复杂的场景或特殊需求下使用。 通过这个实验,学生可以深入理解Spring声明式事务管理的工作原理,以及如何在实际项目中...
Spring 提供了两种事务管理方式:编程式事务管理和声明式事务管理。 1. 编程式事务管理:这是通过编写代码来控制事务的开始、提交和回滚。Spring 提供了PlatformTransactionManager接口,如...
Spring 3.0 提供了两种事务管理配置方法:基于 XML 的事务管理和基于 @Transactional 的事务管理,这两种方法都是为了实现事务管理的目标,分别具有不同的配置方式和优缺点。 基于 XML 的事务管理 这种方法不需要...
标题“Spring事务管理失效原因汇总”指出了本文的核心内容是分析在使用Spring框架进行事务管理时可能遇到的问题及其原因。描述部分进一步说明了事务失效的后果往往不明显,容易在测试环节被忽略,但在生产环境中出现...
在Java企业级应用开发中,Spring框架以其强大的功能和灵活性被广泛应用,特别是在事务管理方面。Spring提供了全面的事务管理解决方案,使得开发者可以方便地控制事务的边界,保证数据的一致性和完整性。本篇将深入...
**声明式事务管理** 是通过在方法上添加`@Transactional`注解,让Spring自动管理事务。这种方式更加简洁,降低了代码的复杂性。`@Transactional`可以设置不同的属性,如`propagation`(传播行为)、`isolation`...
本文将全面分析Spring中的编程式事务管理和声明式事务管理,旨在帮助开发者深入理解这两种事务管理方式,并在实际项目中合理选择。 **编程式事务管理** 编程式事务管理是通过代码直接控制事务的开始、提交、回滚等...
Spring支持两种类型的事务管理:编程式事务管理和声明式事务管理。其中声明式事务管理因其易于使用和维护而被广泛采用。 ##### 1.1 Spring声明式事务介绍 Spring的声明式事务管理是通过配置文件或注解的方式来实现...
Spring 框架的事务管理是其核心特性之一,它为开发者提供了强大的支持,确保了在多线程和并发环境中数据的一致性和完整性。本教程将深入探讨 Spring 的编程式事务管理和声明式事务管理,帮助你理解这两种方式的差异...
Spring事务管理是Spring框架的核心特性之一,主要用于处理应用程序中的数据一致性问题。在Spring中,事务管理分为编程式和声明式两种方式。本篇文章将详细解释Spring事务管理的流程,以及如何通过时序图来理解这一...
Spring 声明式事务管理是Spring框架中的一个重要特性,它允许开发者在不编写任何事务管理代码的情况下,通过配置来管理事务。这种方式极大地简化了事务处理,并提高了代码的可维护性。以下是关于Spring声明式事务...
【Spring框架的事务管理应用分析】 Spring框架是一个在2003年推出的开源项目,它的核心设计理念源于Rod Johnson的《Expert One-on-One J2EE Design and Development》一书中的实用主义J2EE思想。Spring框架主要包括...