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()方法也没有运行。

解决的方法就简单了(两种):

  1. 把这两个方法分开到不同的类中;
  2. 把注解加到类名上面;

结论:

在一个Service内部,事务方法之间的嵌套调用,普通方法和事务方法之间的嵌套调用,都不会开启新的事务.

1. spring采用动态代理机制来实现事务控制,而动态代理最终都是要调用原始对象的,而原始对象在去调用方法时,是不会再触发代理了!

2. Spring的事务管理是通过AOP实现的,其AOP的实现对于非final类是通过cglib这种方式,即生成当前类的一个子类作为代理类,然后在调用其下的方法时,会判断这个方法有没有@Transactional注解,如果有的话,则通过动态代理实现事务管理(拦截方法调用,执行事务等切面)。当b()中调用a()时,发现b()上并没有@Transactional注解,所以整个AOP代理过程(事务管理)不会发生。

附 使用AOP 代理后的方法调用执行流程:

Spring事务管理嵌套事务详解 : 同一个类中,一个方法调用另外一个有事务的方法相关推荐

  1. Spring事务管理--嵌套事务详解

    转载自 https://www.2cto.com/kf/201607/529762.html 一.前言 最近开发程序的时候,出现数据库自增id跳数字情况,无奈之下dba遍查操作日志,没有delete记 ...

  2. Spring事务管理(详解+实例)

    写这篇博客之前我首先读了<Spring in action>,之后在网上看了一些关于Spring事务管理的文章,感觉都没有讲全,这里就将书上的和网上关于事务的知识总结一下,参考的文章如下: ...

  3. Spring进阶(五):Spring事务管理(详解+实例)

    文章目录 一.前言 二.核心接口 2.1 事务管理器 2.1.1 JDBC事务 2.1.2 Hibernate事务 2.1.3 Java持久化API事务(JPA) 2.1.4 Java原生API事务 ...

  4. 编程式事务管理(详解)

    第一章:编程式事务管理(详解) 1. 说明:Spring为了简化事务管理的代码:提供了模板类 TransactionTemplate,所以手动编程的方式来管理事务,只需要使用该模板类即可!! 2. 手 ...

  5. spring的annotation-driven配置事务管理器详解

    来源:http://blog.sina.com.cn/s/blog_8f61307b0100ynfb.html 这篇文章是我从ITeye上复制来的,看了一遍,觉得很深刻,决定把他复制来,对原作者表示感 ...

  6. python类装饰器详解-Python类中的装饰器在当前类中的声明与调用详解

    我的Python环境:3.7 在Python类里声明一个装饰器,并在这个类里调用这个装饰器. 代码如下: class Test(): xx = False def __init__(self): pa ...

  7. java策略管理_详解Java编程中的策略模式

    策略模式属于对象的行为模式.其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换.策略模式使得算法可以在不影响到客户端的情况下发生变化. 策略模式的结构 策略模式 ...

  8. python中getattr详解_Python类中方法getitem和getattr详解

    请分享高手帮小编详解一下Python中的getattr内置函数没明白这个内置函数得意思.麻烦帮小编讲解一下. 其实这个方法最主要的作用是实现反射机制.也就是说可以通过字符串获取方法实例.这样,你就可以 ...

  9. python类初始化详解_python类中super() 的使用解析

    描述 super() 函数是用于调用父类(超类)的一个方法. super 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO).重复 ...

最新文章

  1. 我被裁员了!让保安把身患绝症的我被强赶出公司,亲身经历的噩梦!
  2. 使用CGlib出现java.lang.NoClassDefFoundError: org/objectweb/asm/Type异常
  3. Collections Arrays你会用么?
  4. Windows XP修改操作系统属性中注册到中的名字
  5. srv.sys蓝屏解决补丁_电脑蓝屏重启怎么解决?
  6. linux-centos下源代码安装subversion (svn)
  7. 实时事件日志记录和聚合的平台——Sentry
  8. 开源PagerSlidingTabStrip的使用Tab与ViewPager的完美结合
  9. Struts2.3,s:iterator,c:forEach遍历map中的list集合
  10. 第七季4:网络telnet调试、海思proc文件系统调试接口
  11. 图片维度不匹配_内容审核基础:审核方式、流程与审核维度
  12. Webkit推出新的着色语言whlsl
  13. Scala + Intellij IDEA 环境搭建及编译、打包
  14. php如何自动阅卷,智能评卷系统 自动阅卷软件
  15. 小程序下载PDF等类型文件并保存到本地
  16. 石英晶体振荡器的检定方法
  17. ubuntu phpmyadmin php5.3,ubuntu中怎么下载安装phpmyadmin
  18. 【python与数据分析】实验十三 北京市空气质量
  19. c语言写的一个恶意程序
  20. 常见的DNS攻击与相应的防御措施

热门文章

  1. 在windows下运行spark
  2. GoLang之方法与接口
  3. C语言goto关键字—尽量少用
  4. Getting the right Exception Context from a Memory dump Fixed
  5. ORB-SLAM2中的Loop Closinng中DetectLoopCandidates函数解析
  6. FPGA的ip核之概念和分类
  7. linux的mount命令详解
  8. 《高效程序员的45个习惯》-之一
  9. 全国职业院校技能大赛软件测试题目,我校喜获2018全国职业院校技能大赛“软件测试”赛项一等奖...
  10. g menu i meun_长沙话读“这里”,到底是阁(gó)里还是该(gái)里