一、@EnableTransactionManagement工作原理
開啟Spring事務本質上就是增加了一個Advisor,但我們使用 @EnableTransactionManagement注解來開啟Spring事務是,該注解代理的功能就是向Spring容器中添加了兩個Bean:
(1)AutoProxyRegistrar
(2)ProxyTransactionManagementConfiguration
1
2
(1)AutoProxyRegistrar
主要的作用是向Spring容器中注冊了一個InfrastructureAdvisorAutoProxyCreator的Bean。
而InfrastructureAdvisorAutoProxyCreator繼承了AbstractAdvisorAutoProxyCreator,所以這個類的主要作用就是開啟自動代理的作用,也就是一個BeanPostProcessor,會在初始化后步驟中去尋找Advisor類型的Bean,并判斷當前某個Bean是否有匹配的Advisor,是否需要利用動態代理產生一個代理對象。
(2)ProxyTransactionManagementConfiguration是一個配置類,它又定義了另外三個bean:
二、Spring事務基本執行原理
一個Bean在執行Bean的創建生命周期時,會經過InfrastructureAdvisorAutoProxyCreator的初始化后的方法,會判斷當前Bean對象是否BeanFactoryTransactionAttributeSourceAdvisor匹配,匹配邏輯為判斷該Bean的類上是否存在@Transactional注解,或者類中的某個方法上是否存在@Transactional注解,如果存在則表示該Bean需要進行動態代理產生一個代理對象作為Bean對象。
該代理對象在執行某個方法時,會再次判斷當前執行的方法是否和BeanFactoryTransactionAttributeSourceAdvisor匹配,如果匹配則執行該Advisor中的TransactionInterceptor的invoke()方法,
執行基本流程為:
利用所配置的PlatformTransactionManager事務管理器新建一個數據庫連接
修改數據庫連接的autocommit為false
執行MethodInvocation.proceed()方法,簡單理解就是執行業務方法,其中就會執行sql
如果沒有拋異常,則提交
如果拋了異常,則回滾
三、Spring事務的過程
1、數據庫:建立連接、開啟事務、進行sql操作、成功提交、失敗回滾
2、業務邏輯:準備工作(可以進行前置通知)、開啟事務、事務操作、成功提交(可以后置通知)、失敗回滾(異常通知)
spring的事務是由aop實現的,首先要生成具體的代理對象,然后按照aop流程執行具體
的操作邏輯,正常情況下要通過通知來完成核心功能,但是事務部署通過通知來實現的,
而是通過TransactionInterceptor來實現的,然后調用invoke來實現具體的邏輯。
步驟如下:
1、先做準備工作,解析各個方法上事務相關的屬性,根據具體的屬性來判斷是否開始新事務。
2、當需要開啟的時候獲取數據庫連接,關閉自動提交功能,開啟事務。
3、執行具體的sql邏輯操作,在操作的過程中如果執行失敗會通過 completeTransactionafterthrowing來完成事務的回滾操作,回滾的
具體邏輯是通過dorollback方法實現,實現時也要先獲取連接對象,
然后通過連接對象進行回滾(conn.rollback)。
4、如果執行成功,那么通過completeTransactionafterrunning來完成事務的提交操作,
具體邏輯是通過docommit方法來實現,實現的時候也是先獲取連接,通過連接對象來
進行提交(conn.commit)。
5、最后事務執行完畢需要清除事務相關的事務信息(cleanupTransactioninfo)。
四、Spring事務傳播機制
在開發過程中,經常會出現一個方法調用另外一個方法,那么這里就涉及到了多種場景,比如a()調用b():
a()和b()方法中的所有sql需要在同一個事務中嗎?
a()和b()方法中的所有sql需要在同一個事務中嗎?
a()需要在事務中執行,b()還需要在事務中執行嗎?
或者其他情況
這種情況下就要求Spring事務能支持上面各種場景,這就是Spring事務傳播機制的由來。
那Spring事務傳播機制是如何實現的呢?
先描述其中一個場景中情況,a()在一個事務中執行,調用b()方法時需要新開一個事務執行:
代理對象執行a()方法前,先利用事務管理器新建一個數據庫連接a
將數據庫連接a的autocommit改為false
把數據庫連接a設置到ThreadLocal中
執行a()方法中的sql
執行a()方法過程中,調用了b()方法(注意用代理對象調用b()方法)
a()方法正常執行完,則從ThreadLocal中拿到數據庫連接a進行提交
關于步驟5的一些詳細解釋:
1、代理對象執行b()方法前,判斷出來了當前線程中已經存在一個數據庫連接a了,表示當前線程其實已經擁有一個Spring事務了,則進行掛起
2、掛起就是把ThreadLocal中的數據庫連接a從ThreadLocal中移除,并放入一個掛起資源對象中
3、掛起完成后,再次利用事務管理器新建一個數據庫連接b
4、將數據庫連接b的autocommit改為false
5、把數據庫連接b設置到ThreadLocal中
6、執行b()方法中的sql
7、b()方法正常執行完,則從ThreadLocal中拿到數據庫連接b進行提交
8、提交之后會恢復所掛起的數據庫連接a,這里的恢復,其實只是把在掛起資源對象中所保存的數據庫連接a再次設置到ThreadLocal中
過程中最為重要的是:在執行某個方法時,判斷當前是否已經存在一個事務,就是判斷當前線程的ThreadLocal中是否存在一個數據庫連接對象,如果存在則表示已經存在一個事務了。
————————————————
版權聲明:本文為CSDN博主「填丶涂」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.NET/weixin_51423778/article/details/128226788