Spring中的事務管理為我們做了哪些事?

相信 Java 程序員一定聽過大名鼎鼎的 Spring 框架,Spring 框架的低侵入性,模塊間的解耦,DI 機制,AOP 特性等為程序員大大降低了程序開發的難度,可以說 Spring 目前是最流行的框架技術,佔有很大一部分市場,為廣大程序員帶來巨大的便利。

今天來聊一聊 Spring 中的事務管理為我們做了些什麼事。

由於 DI 和 AOP 是整個 Spring 框架的靈魂,而且今天要講的事務管理也是基於 AOP 的,所以不明白的請先移步至:

11. Aspect Oriented Programming with Spring

先看一段老代碼:

上面代碼是一個完整事務,缺點很明顯,就是比較啰嗦。實際上要做的事情只有向資料庫中插入一條數據。如果每組 jdbc 操作都要去控制 connection,preparedStatement 的狀態,一堆的 try-catch-finally 代碼,看起來很頭疼,而且非常容易寫錯,忘記關閉 connection 也會導致資源耗盡這樣致命的錯誤。

程序員都是很懶的,這些複雜的重複率非常高的代碼最好能交給某個模版去幫忙管理,用技術幹掉重複的事情,從而能更好的專註於自己的業務代碼。

下面介紹一下 Spring 怎樣去幫助我們管理了上面這些狀態,先看一下 Spring 中聲明式事務能簡化到怎樣的程度。

1、需要配置 dataSource, transactionManager, sqlSessionFactory, MapperScannerConfigurer

2、業務邏輯中事務的入口

看上去使用 Spring 幫我們管理的事務是非常簡單的,而且業務代碼簡潔到了極致。

只要我們配置好了相應的 dataSource,transactionManager, sqlSessionFactory, MapperScannerConfigurer,

在需要事務的方法上加上註解 @Transactional 即可。

@Transactional 這個註解裡面有幾個屬性用來描述程序員需要的事務類型。

看一下源碼裡面有如下幾個屬性:

那麼 Spring 框架是怎樣做到的呢?

@Transactional 這個註解的背後有怎樣的邏輯呢?

為什麼那些複雜的狀態控制代碼,資源釋放的代碼都看不到了呢?

將一組 jdbc 操作放入同一個事務需要的幾個步驟:

  1. 開啟事務

  2. jdbc 操作

  3. 成功:提交事務異常:回滾事務
  4. 釋放資源

實際上,正是 Spring 幫助我們做了上述1,3,4三步(第2步使我們的業務代碼)。看一下之前配置的 transactionManager 以及其父類AbstractPlatformTransactionManager,AbstractPlatformTransactionManager繼承了介面 PlatformTransactionManager,而該介面中只有三個方法:

可以看出這三個方法分別對應了1)3)兩個步驟。

繼續看抽象類 AbstractPlatformTransactionManager 中的方法,AbstractPlatformTransactionManager 的方法有很多,其中有幾個方法值得注意:

看到這裡1)3)4)三步都有了方法對應。每個 public 方法又對應了以「do*」開頭各自 protected abstract 方法,這是什麼意思呢?

實際上繼承於AbstractPlatformTransactionManager 的類有很多,如DataSourceTransactionManager , JtaTransactionManager, HibernateTransactionManager 等,不管是哪一個種,總要有 getTransaction,commit,rollback的方法,所以這個三個方法在介面中,不過具體實現方式有所區別,所以具體的實現需要而且是必須在子類中完成。

AbstractPlatformTransactionManager 規定了這三個方法的調用順序,真正的細節在子類中以」do*」開頭的方法中實現,這也正是大多數抽象類的作用所在。

當然 AbstractPlatformTransactionManager 中還有很多其它方法,我們這裡只關注最重要的幾個主幹上方法,也就是介面中規定的方法以及其子類中的實現,這裡子類選取 DataSourceTransactionManager 進行代碼分析。

首先先結合時序圖看一下幾個主要方法的調用:

下面與源碼相結合,先看一下入口處,也就是 AbstractPlatformTransactionManager 中 getTransaction(TransactionStatus status) 方法:

跳轉到子類 doBegin(…) 方法中:

此時 Spring 框架已經幫我們獲取了一個 connetion,並且設置了 autoCommit 為 false。之後調用 service 中的代碼,如果一切順利 Spring 框架將繼續調用 AbstractPlatformTransactionManager 中的 commit(…) 方法,繼續看源碼:

跳轉到子類看下 doCommit(…) 方法具體做了些什麼事情:

現在事務已經提交了,如果是異常的情況,父類中調用方法 robbback(…):

跳轉到子類中看 doRollback(…) 的具體實現:

最後看一下對資源釋放的代碼,父類中 cleanupAfterCompletion(status) 方法調用了 doCleanupAfterCompletion(...):

至此 Spring 幫我們管理的事務,其主要流程和方法已經介紹完了,當然其中還有很多 private 方法和 protected 方法沒有介紹。我想只要把主幹捋清除之後,其他一些方法也很好理解了。

繞了一大圈,實際上還是繞不過開始事務,提交事務,回滾事務三件事,只是這三件事情現在由 Spring 幫助我們在背後默默做好了。

應該感謝 Spring 幫助程序員做了這些繁瑣的事情,可以讓程序員不用擔心資源泄露之類事情,專註於自己的業務邏輯代碼。同時 Spring 框架代碼規範,設計清晰也是程序員非常值得借鑒的地方。

本文作者:謝星星(點融黑幫),目前就職於點融網架構組Backend Architecture團隊,簡單務實的程序猿,寫代碼不給自己挖坑更不能留坑於他人。

本文由@點融黑幫(ID:DianrongMafia)原創發佈於知乎,未經許可,禁止轉載。

推薦閱讀:

Spring和struts2整合詳解
Spring Security(二) -- Spring Security的Filter
Ribbon源碼分析系列(一)
【spring指南系列】計劃任務

TAG:互聯網 | Spring | 架構 |