有这样的一道面试题:在service层调用别的service层的方法,他们的事务可否生效;若是是在同一个类中调用带有@Transactional注解的方法,此时,他们的事务可否生效?
看了许多大神的blog,今天来作一下总结:java
先给出你们答案:面试
(1) 首先先说一下Spring事务管理详解:下面的这篇博客介绍的很清楚了,从基本原理、事务的特性、隔离级别以及事务实现的三种方式spring
Spring事务管理详解异步
http://www.javashuo.com/article/p-qfjpfzgm-ne.htmlthis
(2) 知道了事务的一些知识后,下面说一下@Transactional注解的信息(你们着重看一下4 5 6条的解释)spa
1.在须要事务管理的地方加@Transactional 注解。@Transactional 注解能够被应用于接口定义和接口方法、 类定义和类的 public 方法上。 2.@Transactional 注解只能应用到 public 可见度的方法上。 若是你在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,它也不会报错, 可是这个被注解的方法将不会展现 已配置的事务设置。 3.注意仅仅 @Transactional 注解的出现不足于开启事务行为,它仅仅 是一种元数据。 必须在配置文件中使用配置元素,才真正开启了事务行为。(spring配置文件中,开启声明式事务) 例如能够这么配置: <!--======= 事务配置 Begin ================= --> <!-- 事务管理器(由Spring管理MyBatis的事务) --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!-- 关联数据源 --> <property name="dataSource" ref="dataSource"></property> </bean> <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" /> <!--======= 事务配置 End =================== --> 4.经过 元素的 “proxy-target-class” 属性值来控制是基于接口的仍是基于类的代理被建立。 若是 “proxy-target-class” 属值被设置为 “true”,那么基于类的代理将起做用(这时须要CGLIB库 cglib.jar在CLASSPATH中)。若是 “proxy-target-class” 属值被设置为 “false” 或者这个属性被省略, 那么标准的JDK基于接口的代理将起做用。 5.Spring团队建议在具体的类(或类的方法)上使用 @Transactional 注解,而不要使用在类所要实现的任何接口 上。在接口上使用 @Transactional 注解,只能当你设置了基于接口的代理时它才生效。由于注解是 不能继承 的,这就意味着若是正在使用基于类的代理时,那么事务的设置将不能被基于类的代理所识别,并且对象也将不会被事 务代理所包装。 6.@Transactional的事务开启 ,或者是基于接口的 或者是基于类的代理被建立。因此在同一个类中一个无事务的方法调用另外一个有事务的方法,事务是不会起做用的。若是在有事务的方法中调用另一个有事务的方法,那么事务会起做用,而且共用事务。若是在有事务的方法中调用另一个没有事务的方法,那么事务也会起做用。
不生效的缘由:
当从类外调用没有添加事务的方法a()时,从spring容器获取到的serviceImpl对象实际是包装好的proxy对象,所以调用a()方法的对象是动态代理对象。而在类内部a()调用b()的过程当中,实质执行的代码是this.b(),此处this对象是实际的serviceImpl对象而不是本该生成的代理对象,所以直接调用了b()方法。.net
解决办法:
线程
1. 放到不一样的类中进行调用 2. 在spring配置文件中加入配置 <aop:aspectj-autoproxy/> <aop:aspectj-autoproxy proxy-target-class=“true” expose-proxy=“true” /> 3. 将以前使用普通调用的方法,换成使用代理调用 ((TestService)AopContext.currentProxy()).testTransactional2(); 获取到TestService的代理类,再调用事务方法,强行通过代理类,激活事务切面。 4. 使用异步操做,另外开启一个线程或者将这个消息写入到队列里面,在其余的地方进行处理
感谢我调用连接的几位大神:代理
关于加@Transactional注解的方法之间调用,事务是否生效的问题code
http://www.javashuo.com/article/p-qdjcpiad-no.html
spring的service类调用本身方法事务无效
https://blog.csdn.net/qq_34021712/article/details/75949779
Spring事务不起做用 问题汇总
https://blog.csdn.net/fanrenxiang/article/details/83024436
Spring事务不生效的缘由大解读
http://www.javashuo.com/article/p-rbzkqxir-mw.html
Spring事务嵌套引起的血案---Transaction rolled back because it has been marked as rollback-only