排坑之旅——動態代理給Spring事務種下的坑

慕容千語發表於2018-09-25

前言

Spring的宣告式事務讓我們不在編寫獲得連線、關閉連線、開啟事務、提交事務、回滾事務等程式碼,通過一個簡單的@Transactional註解,就讓我們輕鬆進行事務處理。我們知道Spring事務基於AOP,採用動態代理實現,雖然使用簡單,但是在實際場景中,我們也會遇到一些坑。而往往遇到坑之後,我們都會茫然,這是由於沒有對Spring事務的實現機制做一點了解導致的。因此本篇部落格將從原理的角度分析下動態代理給Spring事務埋下的坑!


從動態代理到Spring事務

UserService:

排坑之旅——動態代理給Spring事務種下的坑
UserService介面

txMethod和txMethod2方法模擬事務方法(相當於@Transactional)

noTxMethod方法是普通方法

UserServiceImpl:

排坑之旅——動態代理給Spring事務種下的坑
UserServiceImpl

在Spring事務中,我們往往是在Service層進行事務控制。

我們在UserServiceImpl中想模擬的是:

一個有事務的方法,去呼叫另一個有事務的方法,會怎麼樣?

一個沒有事務的方法,去呼叫一個有事務的方法,會怎麼樣?

UserHandler:

排坑之旅——動態代理給Spring事務種下的坑
UserHandler

這裡為了簡便,通過方法名稱來判斷是否開啟事務。

顯然,txMethod方法、txMethod2方法都“應該”開啟事務。

UserTest:

排坑之旅——動態代理給Spring事務種下的坑
UserTest

下面,我們來說下執行結果:

proxyInstance.txMethod2()方法,會開啟事務,這沒有問題。

proxyInstance.txMethod()方法,雖然在事務方法txMethod()內部呼叫了txMethod2()事務方法,但是並沒有新開啟事務。

proxyInstance.noTxMethod()方法,雖然在沒有事務的方法noTxMethod()內部呼叫了有事務的txMethod2()方法,但是並沒有開啟事務。

下面讓我們來對應下Spring事務中的現象:

排坑之旅——動態代理給Spring事務種下的坑
Spring事務

上述的情況,說白了,就是在一個Service內部,事務方法之間的巢狀呼叫,普通方法和事務方法之間的巢狀呼叫,都不會開啟新的事務!

為什麼會這樣呢?

其實通過上面的動態代理的程式碼,你應該可以發現:

動態代理最終都是要呼叫原始物件的,而原始物件在去呼叫方法時,是不會再觸發代理了!

那麼如何解決呢?

很簡單,我們完全可以在抽出一個XxxService,在其內部呼叫UserService.txMethod()和UserService.txMethod2()方法即可。總而言之,避免在一個Service內部進行事務方法的巢狀呼叫!(因為動態代理導致這種場景事務失效了。)


好像Spring事務如此簡單,但是背後卻有這些道道,你被坑過麼?


歡迎工作一到五年的Java工程師朋友們加入Java架構開發:878249276

群內提供免費的Java架構學習資料(裡面有高可用、高併發、高效能及分散式、Jvm效能調優、Spring原始碼,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個知識點的架構資料)合理利用自己每一分每一秒的時間來學習提升自己,不要再用"沒有時間“來掩飾自己思想上的懶惰!趁年輕,使勁拼,給未來的自己一個交代!


相關文章