30張圖帶你分析:spring事務源碼 前言 註解事務運行流程 核心對象關係 一、事務配置相關 二、事務運行攔截相關 源碼實現 一、事務配置 二、事務創建 三、事務回滾 四、事務提交 總結

前言

很多人認爲事務很簡單,但是往往在工作中遇到一些事務的坑(尤其是事務方法中嵌套其它事務方法一起使用時)之後,我們卻不知道問題產生的原因和如何有效的解決。

這就需要去分析 Spring的核心源碼 ,最終踏實地找到問題的原因和解決思路。

註解事務運行流程

先來看Spring事務的底層運行流程

核心對象關係

一、事務配置相關

TransactionManagementConfigurationSelector :配置啓動事務啓動(EnableTransactionManagement)時,導入註冊的配置bean。

它包括AutoProxyRegistrar和ProxyTransactionManagementConfiguration兩大配置塊。

AutoProxyRegistrar :負責依賴注入事務的相關屬性配置和注入事務入口類(InfrastructureAdvisorAutoProxyCreator類);

ProxyTransactionManagementConfiguration :負責注入事務相關的Bean, 包括:

  • 事務切面Bean(BeanFactoryTransactionAttributeSourceAdvisor)
  • TransactionAttributeSource(事務配置屬性bean)
  • TransactionInterceptor(事務攔截器bean);

二、事務運行攔截相關

  • AopProxy:Spring AOP 動態代理的基接口,負責定義Proxy的基礎行爲;
  • MethodInterceptor:Spring AOP調用鏈中攔截器的內部核心接口,所有類型的切面最終都會最終包裝成此接口觸發統一攔截;
  • TransactionInterceptor:Spring事務攔截器的核心業務實現,AOP調用鏈也最終觸發它的invoke方法;
  • TransactionManager:Spring管理的基接口,作爲子接口上層接口區分,並沒有定義實際的事務行爲能力;
  • PlatformTransactionManager:繼承TransactionManager,定義事務和基礎行爲;
  • AbstractPlatformTransactionManager:負責實現整個事務管理和運行過程中的公共行爲和通用實現邏輯,它繼承至PlatformTransactionManager接口;

源碼實現

接下來我們來分塊分析一下,Spring事務的源碼,其中的一些坑和重要結論會在這個過程分享。

一、事務配置

TransactionManagementConfigurationSelector.selectImports()負責定義外部加入spring容器的配置類

此方法最終在ConfigurationClassParser中被解析並最終實例化爲bean

AutoProxyRegistrar.registerBeanDefinitions()把InfrastructureAdvisorAutoProxyCreator註冊beandefinition

ProxyTransactionManagementConfiguration.transactionAdvisor()注入事務切面

二、事務創建

實際運行入口之一(還有cglib):JdkDynamicAopProxy..invoke()

ReflectiveMethodInvocation.proceed()切面調用鏈處理核心方法

TransactionInterceptor.invoke()從這裏觸發事務攔截

TransactionAspectSupport.invokeWithinTransaction()實現Spring事務的核心業務

TransactionAspectSupport.determineTransactionManager()定義指定的事務管理器

對於事務管理器,默認使用DataSourceTransactionManager(可配置數據源的事務管理器),也可自定義事務管理器,然後配置數據源即可。

createTransactionIfNecessary()創建事務信息TransactionInfo:其中包括數據源、事務連接(ConnectionHolder)、事務狀態、連接緩存等;

DataSourceTransactionManager.doGetTransaction()獲取事務對象:裏面包含連接包裝和緩存

TransactionSynchronizationManager.getResource()連接線程級緩存:確保當前線程拿到唯一的數據連接

AbstractPlatformTransactionManager.startTransaction()開啓一個新事務

只有newTransaction爲true時,spring纔會做實際的提交或回滾,這裏是一個很重要的點。很多嵌套事務的坑,都是這裏沒有理解清楚。

DataSourceTransactionManager.doBegin()開啓事務核心源碼

TransactionSynchronizationManager.bindResource()設置當前連接和數據源的線程級綁定

三、事務回滾

對於非編程式事務而言,Spring事務的核心實現其實就是用try / catch 包裹事務提交和回滾的範式而已,但提交和回滾裏面的包裝大有講究。

TransactionAspectSupport.completeTransactionAfterThrowing()事務回滾實現

以上截圖中doSetRollbackOnly(),不會在連接上實際設置回滾點,只打個標記(當前事務需要回滾, commit時會使用該標記)!

四、事務提交

AbstractPlatformTransactionManager.commit()事務實際提交源碼這裏

cleanupAfterCompletion()回收連接或恢復事務,這個點耐人尋味:當事務傳播屬性爲Require_New時,會暫時掛起之前的連接,然後創建新連接;當新連接提交或回滾後,通過這個方法恢復之前連接和狀態!!!!

OK事務到這裏,我根據源碼分享一些關於嵌套子事務的甜點:

  • 嵌套事務過程,中間有任何異常,只要沒被屏蔽,則都會上拋,不會再執行後續代碼;
  • 只要設置Require_New事務傳播屬性,則每個Transactional註解方法內部都會單獨提交或回滾;
  • 嵌套事務會在除首個Transactional註解外的子事務中創建savepoint回滾點;
  • 設置savepoint回滾點後,回滾時會回滾包括當前方法之前的所有事務;若只需回滾當前方法,則在最外層事務方法加try{}catch(){//不拋出異常};
  • 每個事務的對象都是不一樣的,事務狀態可能不一樣,但連接可能是同一個;

總結

今天的Spring事務源碼就暫時分享到這裏,事務這塊只有一層的事務很簡單,但當嵌套了多個(層)子事務(而且每個子事務的事務傳播屬性可能不一樣的情況下)時就當另當別論了。

需要我們根據源碼的規律去分析每層子事務該如何流轉!!所以需要把這塊的源碼搞熟,遇到複雜的嵌套事務分析原因,那問題就不大了。

來源:https://www.tuicool.com/articles/YvaIfmF

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