spring事務之事務掛起和事務恢復源碼解讀
事務掛起和事務恢復源碼解讀
在學習spring事務的時候,一定會涉及到一個概念,無法避免的,就是事務掛起和事務恢復
對于事務掛起和事務恢復,可以簡單的描述一下,是這樣的
- 1.首先我們假設有兩個類,A類和B類,兩個類中的字段是一模一樣的,A類表示當前事務,B類表示備份事務
- 2.如果我開啟一個事務,會把當前事務信息,存入到A類中,如果我這時候要進行事務掛起
- 3.事務掛起:就會把A類中當前事務的信息,賦值到B類中,然后在創(chuàng)建一個新事務的時候,會賦值到A類中
- 4.恢復事務:如果此時我當前事務執(zhí)行完畢了,需要恢復原來的事務,就只需要將A類清空,然后將B類中的數(shù)據(jù)信息賦值到A類,此時A事務就會再次生效
我覺得可以理解為就是倒騰了一手
事務掛起源碼
org.springframework.transaction.support.AbstractPlatformTransactionManager#handleExistingTransaction
我們直接跳入到這個方法中來看,這個方法是在當前事務存在的時候,會進入到這個方法來處理,執(zhí)行鏈路是這樣的
org.springframework.transaction.interceptor.TransactionInterceptor#invoke
org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction
org.springframework.transaction.interceptor.TransactionAspectSupport#createTransactionIfNecessary
org.springframework.transaction.support.AbstractPlatformTransactionManager#getTransaction
org.springframework.transaction.support.AbstractPlatformTransactionManager#handleExistingTransaction
正常的話,一個事務方法的執(zhí)行是這個鏈路,自己debug看下即可,但是要進入到這個方法中,有一個前提,就是當前事務已存在,然后又調(diào)用了另外一個事務方法,才會進入到這里
我們以PROPAGATION_REQUIRES_NEW這個級別的傳播機制為例,為什么以這個為例,因為這個傳播機制,在當前事務存在的時候,是會將當前事務掛起,然后開啟一個新的事務,也正好可以看下spring是如何掛起事務,并創(chuàng)建新事務的
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) { if (debugEnabled) { logger.debug("Suspending current transaction, creating new transaction with name [" + definition.getName() + "]"); } /** * 這里是掛起事務的操作,掛起事務的話,會把事務管理器中的屬性設置為null * ,然后將事務管理器中的屬性暫時存儲到suspendedResourceHolder中 */ SuspendedResourcesHolder suspendedResources = suspend(transaction); try { boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER); DefaultTransactionStatus status = newTransactionStatus( definition, transaction, true, newSynchronization, debugEnabled, suspendedResources); // 開啟事務 doBegin(transaction, definition); // 將事務綁定到線程中 prepareSynchronization(status, definition); return status; } catch (RuntimeException | Error beginEx) { /** * 如果在開啟新的事務的時候,異常了,就會在下面這個方法中,將事務恢復(和上面掛起是相對的) * ,其實就是把suspendResourceHolder中的屬性重新賦值到TransactionSynchronizationManager */ resumeAfterBeginException(transaction, suspendedResources, beginEx); throw beginEx; } }
由于這個方法中,代碼比較多,我就刪減了一部分,只留下了propagation_requires_new這個傳播機制的代碼
可以看到,會先調(diào)用suspend(transaction)將當前事務掛起,然后再下面的doBegin()再開啟一個新的事務,然后通過prepareSynchronization(),將事務相關信息放入到threadLocal中
suspend(transaction)
/** * 這是掛起事務的源碼 * 所謂的事務掛起:就是將當前事務管理器中的相關屬性,保存到suspendedResourceHolder中 */ @Nullable protected final SuspendedResourcesHolder suspend(@Nullable Object transaction) throws TransactionException { /** * 1.如果當前事務是active狀態(tài),就將事務掛起,掛起的操作其實也簡單 * 將當前事務的屬性信息暫存到SuspendedResourcesHolder中,然后將當前事務的屬性設置為null */ if (TransactionSynchronizationManager.isSynchronizationActive()) { List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization(); try { Object suspendedResources = null; if (transaction != null) { suspendedResources = doSuspend(transaction); } /** * 1.1 下面就是掛起事務的操作,將事務同步管理器中的屬性置為null * , 然后將配置信息,存儲到suspendedResources中,以便在恢復事務的時候,可以恢復 */ String name = TransactionSynchronizationManager.getCurrentTransactionName(); TransactionSynchronizationManager.setCurrentTransactionName(null); boolean readOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly(); TransactionSynchronizationManager.setCurrentTransactionReadOnly(false); Integer isolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel(); TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(null); boolean wasActive = TransactionSynchronizationManager.isActualTransactionActive(); TransactionSynchronizationManager.setActualTransactionActive(false); return new SuspendedResourcesHolder( suspendedResources, suspendedSynchronizations, name, readOnly, isolationLevel, wasActive); } catch (RuntimeException | Error ex) { /** * 2.如果掛起事務失敗,就需要進行回滾,就是將suspendedResourcesHolder * 中的屬性重新賦值到TransactionSynchronizationManager中 */ // doSuspend failed - original transaction is still active... doResumeSynchronization(suspendedSynchronizations); throw ex; } } else if (transaction != null) { // Transaction active but no synchronization active. Object suspendedResources = doSuspend(transaction); return new SuspendedResourcesHolder(suspendedResources); } else { // Neither transaction nor synchronization active. return null; } }
這是suspend的源碼,可以看到,在1.1這個注釋位置,會獲取到當前事務的屬性信息,然后在下面,會new SuspendedResourcesHolder(),將當前事務屬性信息放入到這里面
再下面,就是一些異常的判斷和處理,我們可以認為,這個方法就是把事務的屬性信息存入到了SuspendedResourcesHolder對象中
newTransactionStatus()
這個方法也很重要,會把剛才創(chuàng)建的suspend對象,放入到DefaultTransactionStatus類中,這里我猜是為了在后面事務恢復的時候用的
doBegin()
在doBegin()方法中,主要是重新獲取一個數(shù)據(jù)庫連接,然后設置連接的相關信息,比如:非自動提交等
然后將連接信息存入到TransactionSynchronizationManager對象中
我們可以簡單認為doBegin()就是重新開啟了一個事務連接
事務恢復
前面講的是事務掛起,下面來說事務恢復,事務恢復,就是在事務提交或者回滾的時候,會進行事務恢復的處理
這里直接貼了一張圖,是事務提交和事務回滾的處理流程,最終都會調(diào)用到cleanupAfterCompletion()方法,這個方法就是事務恢復的代碼
private void cleanupAfterCompletion(DefaultTransactionStatus status) { status.setCompleted(); if (status.isNewSynchronization()) { TransactionSynchronizationManager.clear(); } if (status.isNewTransaction()) { doCleanupAfterCompletion(status.getTransaction()); } if (status.getSuspendedResources() != null) { if (status.isDebug()) { logger.debug("Resuming suspended transaction after completion of inner transaction"); } Object transaction = (status.hasTransaction() ? status.getTransaction() : null); resume(transaction, (SuspendedResourcesHolder) status.getSuspendedResources()); } }
在這個代碼中,前面是一些邏輯處理,應該是對當前事務進行清除的操作,需要關注的是最后一行代碼,resume()方法
protected final void resume(@Nullable Object transaction, @Nullable SuspendedResourcesHolder resourcesHolder) throws TransactionException { if (resourcesHolder != null) { Object suspendedResources = resourcesHolder.suspendedResources; if (suspendedResources != null) { doResume(transaction, suspendedResources); } List<TransactionSynchronization> suspendedSynchronizations = resourcesHolder.suspendedSynchronizations; if (suspendedSynchronizations != null) { TransactionSynchronizationManager.setActualTransactionActive(resourcesHolder.wasActive); TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(resourcesHolder.isolationLevel); TransactionSynchronizationManager.setCurrentTransactionReadOnly(resourcesHolder.readOnly); TransactionSynchronizationManager.setCurrentTransactionName(resourcesHolder.name); doResumeSynchronization(suspendedSynchronizations); } } }
這里可以看到,是從resourcesHolder中取一些參數(shù)賦值到TransactionSynchronizationManager中;SuspendedResourcesHolder是哪個對象呢?
就是前面事務掛起的時候,將當前事務參數(shù)信息賦值到的一個對象
所以
我們可以認為,事務掛起就是將事務賦值到一個臨時對象中,事務恢復就是從臨時對象中,將事務屬性信息賦值到當前事務中
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
Spring Boot整合Spring Security簡單實現(xiàn)登入登出從零搭建教程
這篇文章主要給大家介紹了關于Spring Boot整合Spring Security簡單實現(xiàn)登入登出從零搭建的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面來一起看看吧2018-09-09淺析Java中關鍵詞volatile底層的實現(xiàn)原理
在 Java 并發(fā)編程中,有 3 個最常用的關鍵字:synchronized、ReentrantLock 和 volatile,這篇文章主要來和大家聊聊volatile底層的實現(xiàn)原理,感興趣的可以了解下2024-02-02Java基于JDBC實現(xiàn)事務,銀行轉(zhuǎn)賬及貨物進出庫功能示例
這篇文章主要介紹了Java基于JDBC實現(xiàn)事務,銀行轉(zhuǎn)賬及貨物進出庫功能,較為詳細的分析了事務操作的原理、實現(xiàn)方法及java基于jdbc連接數(shù)據(jù)庫實現(xiàn)銀行事務操作的相關技巧,需要的朋友可以參考下2017-12-12