Java開發Spring的統一事務模型,深入講解

Java開發Spring的統一事務模型,深入講解

鎮樓小姐姐

可獲得兩大新人禮包

36份一線互聯網Java面試電子書

84個Java稀缺面試題視頻


Spring事務的知識體系

進入主題之前,先來了解一下Spring事務都有哪些內容:

Java開發Spring的統一事務模型,深入講解

Spring事務包含對分佈式事務和單機事務的支持,我們用的比較多的是單機事務,也就是隻操作一個數據庫的事務。

編程式事務模型裡面涉及到很多知識點,比如統一事務模型、事務傳播級別、事務隔離級別等。

我們今天要講的是其中一點,統一事務模型。

希望這次的分享能夠讓大家,對Spring事務有一個整體性的認識。

不僅僅是Template

Spring的統一事務模型,解決的一個核心問題,就是不管你用的是什麼數據訪問方式,Hibernate、MyBatis抑或是JDBC,你的Service層的代碼都是一樣的,不需要做任何變動。

使用@Transactional註解的,相信大家都用過,而且由於註解的實現比較隱晦,不利於我們理解原理,這裡就不演示。

下面介紹編程式事務模型,TransactionTemplate:

Java開發Spring的統一事務模型,深入講解

不管後面你的Dao實現如何變化,上面這一段Service代碼都無需修改,而且依舊可以保持事務的邏輯。

Spring是怎麼做到的呢?

有人說,是模板模式。

點開TransactionTemplate,的確是封裝了事務操作的“套路”:

Java開發Spring的統一事務模型,深入講解

但是細看就會發現,這和我們傳統的template模式還有點不同。

傳統的template,一般會有一個抽象類,抽象類裡封裝了一系列有規律的套路,然後有些套路是抽象的,需要你自己去實現:

Java開發Spring的統一事務模型,深入講解

而TransactionTemplate,它已經是一個具體的類,無需實現任何方法,拿來即用。

但仔細看,就會發現裡面有一個叫transactionManager的傢伙,出鏡率特別高,它幫TransactionTemplate做了很多事情。

點開一個,這傢伙是個叫PlatformTransactionManager的接口:

Java開發Spring的統一事務模型,深入講解

恍然大悟,你只需給TransactionTemplate傳一個PlatformTransactionManager的具體實現,也就是告訴TransactionTemplate,事務創建、提交、回滾的策略,它就可以按照自己的那套流程,完成事務的操作。

這其實是策略模式,這其實是模板+策略的雙劍合璧。

針對不同的廠商,只需要提供不同的PlatformTransactionManager實現即可。

比如對於MyBatis,就用DataSourceTxManager,對於Hibernate,就用HibernateTxManager:

Java開發Spring的統一事務模型,深入講解

不同廠商在實現的時候,按照自己對應的事務操作方式,進行實現即可。

比如DataSourceTxManager,創建事務的時候,new了一個自己的事務對象,最後返回一個Object類型,在commit的時候,再把這個Object,強轉成自己的事務對象:

Java開發Spring的統一事務模型,深入講解

HibernateTxManager也是如此:

Java開發Spring的統一事務模型,深入講解

我們在使用的時候,只需要通過Spring IOC,告訴Spring,要注入哪個TransactionManager,要使用哪種策略即可

connection-pass

瞭解完Spring是如何實現統一的事務模型,不知道你是否也有疑問,既然是事務,那就要保證事務裡的所有dao操作,都要使用同一個數據庫連接進行操作,但是我們在寫代碼的時候,並不需要給dao傳入connection對象:

Java開發Spring的統一事務模型,深入講解

Spring又是怎麼做到的?

答案是ThreadLocal。

通過ThreadLocal,在同一個線程中共享connection。

這很好理解,關鍵是,這是一個什麼樣的ThreadLocal?填空題。

Java開發Spring的統一事務模型,深入講解

也許你和我一開始想的一樣,認為這裡面放到就是connection對象。

直接放connection對象會有一個問題,那就是當你事務裡面涉及到對多個數據庫進行操作時,後面的操作取到的都是第一個數據庫操作放進去的connection:

Java開發Spring的統一事務模型,深入講解

如上圖,假設deleteAll操作的是db1,那麼它創建了針對db1的connection,然後放進ThreadLocal,然後save,本來是想操作db2的,結果它從threadLocal裡拿到的,卻是剛剛deleteAll時,放進去的操作db1的connection,卒。

實際上,Spring在ThreadLocal裡頭,放的是一個Map。key是dataSource,value才是connection.

Java開發Spring的統一事務模型,深入講解

如何新開一個事務

Java開發Spring的統一事務模型,深入講解

然而,按照之前的理論,如果每次都是從ThreadLocal裡去獲取connection,那麼永遠拿到的都是舊的事務,不會創建新事務。

Spring又是如何實現新開事務的呢?

很簡單,鏈表。

一開始,舊事務綁定在當前線程:

Java開發Spring的統一事務模型,深入講解

當需要新開事務時,先將原來的事務解綁:

Java開發Spring的統一事務模型,深入講解

然後new一個新的事務:

Java開發Spring的統一事務模型,深入講解

接著將新的事務指向舊事務:

Java開發Spring的統一事務模型,深入講解

最後將新事務綁定到當前線程:

Java開發Spring的統一事務模型,深入講解

之所以需要將新事務指向舊事務,形成一個事務鏈,是因為新事務在提交或者回滾之後,還需要恢復舊事務:

Java開發Spring的統一事務模型,深入講解

Java開發Spring的統一事務模型,深入講解

這一塊邏輯對應的代碼:

Java開發Spring的統一事務模型,深入講解

Java開發Spring的統一事務模型,深入講解

總結

這個星期看的Spring事務,不僅僅是解答了我對Spring事務的一些疑惑,還學到了一些挺巧妙的編程招式,比如模板模式竟然可以和策略模式一起使用。

總結一下:

  • Spring如何實現統一的事務模型:Template + Strategy
  • 如何在方法間共享Connection:ThreadLocal
  • 如何掛起和恢復線程:鏈表
  • 提到的類:
  • TransactionTemplate 事務模板
  • PlatformTransactionManager 事務操作策略接口
  • AbstractPlatformTransactionManager 事務操作策略抽象類
  • DataSourceTxManager 具體策略,適用於JDBC/MyBatis
  • HibernateTxManager 具體策略,適用於Hibernate
  • TxSynManager 事務同步管理器,在線程中同步數據庫連接等信息
  • DataSourceUtils 數據庫操作Utils


分享到:


相關文章: