spring service層方法調用同類中的方法 事務不生效

有這樣的一道面試題:在service層調用別的service層的方法,他們的事務可否生效;若是是在同一個類中調用帶有@Transactional註解的方法,此時,他們的事務可否生效?
看了許多大神的blog,今天來作一下總結:java

先給出你們答案:面試

  • 不一樣類之間的方法調用,如類A的方法a()調用類B的方法b(),這種狀況事務是正常起做用的。只要方法a()或b()配置了事務,運行中就會開啓事務,產生代理。
  • 同一類內方法調用,不管被調用的b()方法是否配置了事務,此事務在被調用時都將不生效。


(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

http://www.javashuo.com/article/p-qgfwxync-a.html

相關文章
相關標籤/搜索