有這樣的一道面試題:在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