Spring事务管理嵌套事务详解 : 同一个类中,一个方法调用另外一个有事务的方法
Spring 事务机制回顾
Spring事务一个被讹传很广说法是:一个事务方法不应该调用另一个事务方法,否则将产生两个事务. 结果造成开发人员在设计事务方法时束手束脚,生怕一不小心就踩到地雷。
其实这是不认识Spring事务传播机制而造成的误解,Spring对事务控制的支持统一在TransactionDefinition类中描述,该类有以下 几个重要的接口方法:
除了事务的传播行为外,事务的其他特性Spring是借助底层资源的功能来完成的,Spring无非只充当个代理的角色。但是事务的传播行为却是Spring凭借自身的框架提供的功能 ;
Spring事务传播属性:
所谓事务传播行为就是多个事务方法相互调用时,事务如何在这些方法间传播。Spring支持以下7种事务传播行为
Spring事务传播属性:
1.propagation-required: 支持当前事务,如果有就加入当前事务中;如果当前方法没有事务,就新建一个事务;
2.propagation-supports: 支持当前事务,如果有就加入当前事务中;如果当前方法没有事务,就以非事务的方式执行;
3.propagation-mandatory: 支持当前事务,如果有就加入当前事务中;如果当前没有事务,就抛出异常;
4.propagation-requires_new: 新建事务,如果当前存在事务,就把当前事务挂起;如果当前方法没有事务,就新建事务;
5.propagation-not-supported: 以非事务方式执行,如果当前方法存在事务就挂起当前事务;如果当前方法不存在事务,就以非事务方式执行;
6.propagation-never: 以非事务方式执行,如果当前方法存在事务就抛出异常;如果当前方法不存在事务,就以非事务方式执行;
7.propagation-nested: 如果当前方法有事务,则在嵌套事务内执行;如果当前方法没有事务,则与required操作类似;
前六个策略类似于EJB CMT,第七个(PROPAGATION_NESTED)是Spring所提供的一个特殊变量。
它要求事务管理器或者使用JDBC 3.0 Savepoint API提供嵌套事务行为(如Spring的DataSourceTransactionManager)
在同一个类中,一个方法调用另外一个有注解(比如@Async,@Transational)的方法,注解是不会生效的
代码示例:
例子中,有两方法,一个有@Transational注解,一个没有。如果调用了有注解的addPerson()方法,会启动一个Transaction;如果调用updatePersonByPhoneNo(),因为它内部调用了有注解的addPerson(),如果你以为系统也会为它启动一个Transaction,那就错了,实际上是没有的
@Service
public class PersonServiceImpl implements PersonService {@AutowiredPersonDao personDao;@Override@Transactionalpublic boolean addPerson(Person person) {boolean result = personDao.insertPerson(person)>0 ? true : false;return result;}@Override//@Transactionalpublic boolean updatePersonByPhoneNo(Person person) {boolean result = personDao.updatePersonByPhoneNo(person)>0 ? true : false;addPerson(person); //测试同一个类中@Transactional是否起作用return result;}
}
原因:
spring 在扫描bean的时候会扫描方法上是否包含@Transactional注解,如果包含,spring会为这个bean动态地生成一个子类(即代理类,proxy),代理类是继承原来那个bean的。此时,当这个有注解的方法被调用的时候,实际上是由代理类来调用的,代理类在调用之前就会启动transaction。然而,如果这个有注解的方法是被同一个类中的其他方法调用的,那么该方法的调用并没有通过代理类,而是直接通过原来的那个bean,所以就不会启动transaction,我们看到的现象就是@Transactional注解无效。
为什么一个方法a()调用同一个类中另外一个方法b()的时候,b()不是通过代理类来调用的呢?可以看下面的例子(为了简化,用伪代码表示):
@Service
class A{@Transactinalmethod b(){...}method a(){ //标记1b();}
}//Spring扫描注解后,创建了另外一个代理类,并为有注解的方法插入一个startTransaction()方法:
class proxy$A{A objectA = new A();method b(){ //标记2startTransaction();objectA.b();}method a(){ //标记3objectA.a(); //由于a()没有注解,所以不会启动transaction,而是直接调用A的实例的a()方法}
}
当我们调用A的bean的a()方法的时候,也是被proxy$A拦截,执行proxy$A.a()(标记3),然而,由以上代码可知,这时候它调用的是objectA.a(),也就是由原来的bean来调用a()方法了,所以代码跑到了“标记1”。由此可见,“标记2”并没有被执行到,所以startTransaction()方法也没有运行。
解决的方法就简单了(两种):
- 把这两个方法分开到不同的类中;
- 把注解加到类名上面;
结论:
在一个Service内部,事务方法之间的嵌套调用,普通方法和事务方法之间的嵌套调用,都不会开启新的事务.
1. spring采用动态代理机制来实现事务控制,而动态代理最终都是要调用原始对象的,而原始对象在去调用方法时,是不会再触发代理了!
2. Spring的事务管理是通过AOP实现的,其AOP的实现对于非final类是通过cglib这种方式,即生成当前类的一个子类作为代理类,然后在调用其下的方法时,会判断这个方法有没有@Transactional注解,如果有的话,则通过动态代理实现事务管理(拦截方法调用,执行事务等切面)。当b()中调用a()时,发现b()上并没有@Transactional注解,所以整个AOP代理过程(事务管理)不会发生。
附 使用AOP 代理后的方法调用执行流程:
Spring事务管理嵌套事务详解 : 同一个类中,一个方法调用另外一个有事务的方法相关推荐
- Spring事务管理--嵌套事务详解
转载自 https://www.2cto.com/kf/201607/529762.html 一.前言 最近开发程序的时候,出现数据库自增id跳数字情况,无奈之下dba遍查操作日志,没有delete记 ...
- Spring事务管理(详解+实例)
写这篇博客之前我首先读了<Spring in action>,之后在网上看了一些关于Spring事务管理的文章,感觉都没有讲全,这里就将书上的和网上关于事务的知识总结一下,参考的文章如下: ...
- Spring进阶(五):Spring事务管理(详解+实例)
文章目录 一.前言 二.核心接口 2.1 事务管理器 2.1.1 JDBC事务 2.1.2 Hibernate事务 2.1.3 Java持久化API事务(JPA) 2.1.4 Java原生API事务 ...
- 编程式事务管理(详解)
第一章:编程式事务管理(详解) 1. 说明:Spring为了简化事务管理的代码:提供了模板类 TransactionTemplate,所以手动编程的方式来管理事务,只需要使用该模板类即可!! 2. 手 ...
- spring的annotation-driven配置事务管理器详解
来源:http://blog.sina.com.cn/s/blog_8f61307b0100ynfb.html 这篇文章是我从ITeye上复制来的,看了一遍,觉得很深刻,决定把他复制来,对原作者表示感 ...
- python类装饰器详解-Python类中的装饰器在当前类中的声明与调用详解
我的Python环境:3.7 在Python类里声明一个装饰器,并在这个类里调用这个装饰器. 代码如下: class Test(): xx = False def __init__(self): pa ...
- java策略管理_详解Java编程中的策略模式
策略模式属于对象的行为模式.其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换.策略模式使得算法可以在不影响到客户端的情况下发生变化. 策略模式的结构 策略模式 ...
- python中getattr详解_Python类中方法getitem和getattr详解
请分享高手帮小编详解一下Python中的getattr内置函数没明白这个内置函数得意思.麻烦帮小编讲解一下. 其实这个方法最主要的作用是实现反射机制.也就是说可以通过字符串获取方法实例.这样,你就可以 ...
- python类初始化详解_python类中super() 的使用解析
描述 super() 函数是用于调用父类(超类)的一个方法. super 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO).重复 ...
最新文章
- 我被裁员了!让保安把身患绝症的我被强赶出公司,亲身经历的噩梦!
- 使用CGlib出现java.lang.NoClassDefFoundError: org/objectweb/asm/Type异常
- Collections Arrays你会用么?
- Windows XP修改操作系统属性中注册到中的名字
- srv.sys蓝屏解决补丁_电脑蓝屏重启怎么解决?
- linux-centos下源代码安装subversion (svn)
- 实时事件日志记录和聚合的平台——Sentry
- 开源PagerSlidingTabStrip的使用Tab与ViewPager的完美结合
- Struts2.3,s:iterator,c:forEach遍历map中的list集合
- 第七季4:网络telnet调试、海思proc文件系统调试接口
- 图片维度不匹配_内容审核基础:审核方式、流程与审核维度
- Webkit推出新的着色语言whlsl
- Scala + Intellij IDEA 环境搭建及编译、打包
- php如何自动阅卷,智能评卷系统 自动阅卷软件
- 小程序下载PDF等类型文件并保存到本地
- 石英晶体振荡器的检定方法
- ubuntu phpmyadmin php5.3,ubuntu中怎么下载安装phpmyadmin
- 【python与数据分析】实验十三 北京市空气质量
- c语言写的一个恶意程序
- 常见的DNS攻击与相应的防御措施
热门文章
- 在windows下运行spark
- GoLang之方法与接口
- C语言goto关键字—尽量少用
- Getting the right Exception Context from a Memory dump Fixed
- ORB-SLAM2中的Loop Closinng中DetectLoopCandidates函数解析
- FPGA的ip核之概念和分类
- linux的mount命令详解
- 《高效程序员的45个习惯》-之一
- 全国职业院校技能大赛软件测试题目,我校喜获2018全国职业院校技能大赛“软件测试”赛项一等奖...
- g menu i meun_长沙话读“这里”,到底是阁(gó)里还是该(gái)里