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

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

先給出大家答案:

  • 不同類之間的方法調用,如類A的方法a()調用類B的方法b(),這種情況事務是正常起作用的。只要方法a()或b()配置了事務,運行中就會開啓事務,產生代理。
  • 同一類內方法調用,無論被調用的b()方法是否配置了事務,此事務在被調用時都將不生效。
  1. 首先先說一下Spring事務管理詳解:下面的這篇博客介紹的很清楚了,從基本原理、事務的特性、隔離級別以及事務實現的三種方式
    Spring事務管理詳解
  2. 知道了事務的一些知識後,下面說一下@Transactional註解的信息(大家着重看一下4 5 6條的解釋)
1.在需要事務管理的地方加@Transactional 註解。@Transactional 註解可以被應用於接口定義和接口方法、類定義和類的 public 方法上。

2.@Transactional 註解只能應用到 public 可見度的方法上。 如果你在 protected、private 或者 package-visible 的方法上使用 @Transactional 註解,它也不會報錯, 但是這個被註解的方法將不會展示已配置的事務設置。

3.注意僅僅 @Transactional 註解的出現不足於開啓事務行爲,它僅僅 是一種元數據。必須在配置文件中使用配置元素,才真正開啓了事務行爲。(spring配置文件中,開啓聲明式事務)

4.通過 元素的 “proxy-target-class” 屬性值來控制是基於接口的還是基於類的代理被創建。如果 “proxy-target-class” 屬值被設置爲 “true”,那麼基於類的代理將起作用(這時需要CGLIB庫cglib.jar在CLASSPATH中)。如果 “proxy-target-class” 屬值被設置爲 “false” 或者這個屬性被省略,那麼標準的JDK基於接口的代理將起作用。

5.Spring團隊建議在具體的類(或類的方法)上使用 @Transactional 註解,而不要使用在類所要實現的任何接口上。在接口上使用 @Transactional 註解,只能當你設置了基於接口的代理時它才生效。因爲註解是 不能繼承 的,這就意味着如果正在使用基於類的代理時,那麼事務的設置將不能被基於類的代理所識別,而且對象也將不會被事務代理所包裝。

6.@Transactional的事務開啓 ,或者是基於接口的 或者是基於類的代理被創建。所以在同一個類中一個無事務的方法調用另一個有事務的方法,事務是不會起作用的。
  1. 不生效的原因:

       當從類外調用方法a()時,從spring容器獲取到的serviceImpl對象實際是包裝好的proxy對象,因此調用a()方法的對象是動態代理對象。而在類內部a()調用b()的過程中,實質執行的代碼是this.b(),此處this對象是實際的serviceImpl對象而不是本該生成的代理對象,因此直接調用了b()方法。

  1. 解決辦法:
  1. 放到不同的類中進行調用
  2. 在spring配置文件中加入配置
    <aop:aspectj-autoproxy/>
    <aop:aspectj-autoproxy proxy-target-class=“true” expose-proxy=“true” />
  3. 將之前使用普通調用的方法,換成使用代理調用
    ((TestService)AopContext.currentProxy()).testTransactional2();
    獲取到TestService的代理類,再調用事務方法,強行經過代理類,激活事務切面。
  4. 使用異步操作,另外開啓一個線程或者將這個消息寫入到隊列裏面,在其他的地方進行處理

感謝我調用鏈接的幾位大神:

關於加@Transactional註解的方法之間調用,事務是否生效的問題
spring的service類調用自己方法事務無效
Spring事務不起作用 問題彙總

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章