Spring源碼解析之事務(wù)傳播特性
一、使用方式
可以采用Transactional,配置propagation即可。
打開(kāi)org.springframework.transaction.annotation.Transactional
可見(jiàn)默認(rèn)傳播特性是REQUIRED
。
/** * The transaction propagation type. * <p>Defaults to {@link Propagation#REQUIRED}. * @see org.springframework.transaction.interceptor.TransactionAttribute#getPropagationBehavior() */ Propagation propagation() default Propagation.REQUIRED;
二、getTransaction
顧名思義,此項(xiàng)屬性是在事務(wù)存在交互時(shí)生效。那么到底是如何生效的呢,核心源碼位于org.springframework.transaction.support.AbstractPlatformTransactionManager
。核心入口是getTransaction方法。
@Override public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException { Object transaction = doGetTransaction(); // Cache debug flag to avoid repeated checks. boolean debugEnabled = logger.isDebugEnabled(); // if (definition == null) { // Use defaults if no transaction definition given. definition = new DefaultTransactionDefinition(); } //已經(jīng)存在事務(wù) 根據(jù)事務(wù)傳播特性進(jìn)行處理 if (isExistingTransaction(transaction)) { // Existing transaction found -> check propagation behavior to find out how to behave. return handleExistingTransaction(definition, transaction, debugEnabled); } // Check definition settings for new transaction. if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) { throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout()); } // No existing transaction found -> check propagation behavior to find out how to proceed. //當(dāng)前不存在事務(wù) MANDATORY直接拋出異常 if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) { throw new IllegalTransactionStateException( "No existing transaction found for transaction marked with propagation 'mandatory'"); } //REQUIRED REQUIRES_NEW NESTED則會(huì)新建一個(gè)事務(wù) else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED || definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW || definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) { SuspendedResourcesHolder suspendedResources = suspend(null); if (debugEnabled) { logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition); } 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 ex) { resume(null, suspendedResources); throw ex; } } else { xxx } }
可以看到,在當(dāng)前不存在事務(wù)時(shí),
- MANDATORY 直接拋出異常
- REQUIRED REQUIRES_NEW NESTED 自動(dòng)新建一個(gè)事務(wù)。
那么存在事務(wù)時(shí)是如何處理的呢?
三、handleExistingTransaction
/** * 處理已經(jīng)存在事務(wù)的情況 * Create a TransactionStatus for an existing transaction. */ private TransactionStatus handleExistingTransaction( TransactionDefinition definition, Object transaction, boolean debugEnabled) throws TransactionException { //NEVER 已經(jīng)存在事務(wù) 直接拋出異常 if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) { throw new IllegalTransactionStateException( "Existing transaction found for transaction marked with propagation 'never'"); } //NOT_SUPPORTED 注意prepareTransactionStatus方法參數(shù)傳遞事務(wù)的時(shí)候傳遞參數(shù)為null,所以是采用非事務(wù)方式運(yùn)行。執(zhí)行會(huì)掛起當(dāng)前事務(wù)。 if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) { if (debugEnabled) { logger.debug("Suspending current transaction"); } Object suspendedResources = suspend(transaction); boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS); return prepareTransactionStatus( definition, null, false, newSynchronization, debugEnabled, suspendedResources); } //REQUIRES_NEW 新建事務(wù) 會(huì)掛起當(dāng)前事務(wù) if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) { if (debugEnabled) { logger.debug("Suspending current transaction, creating new transaction with name [" + definition.getName() + "]"); } 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) { resumeAfterBeginException(transaction, suspendedResources, beginEx); throw beginEx; } } //NESTED 處理嵌套事務(wù) if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) { // 檢查是否支持嵌套事務(wù) if (!isNestedTransactionAllowed()) { throw new NestedTransactionNotSupportedException( "Transaction manager does not allow nested transactions by default - " + "specify 'nestedTransactionAllowed' property with value 'true'"); } if (debugEnabled) { logger.debug("Creating nested transaction with name [" + definition.getName() + "]"); } // 支持的話則采用Savepoint 否則開(kāi)啟新事務(wù) 并不會(huì)掛起當(dāng)前事務(wù) if (useSavepointForNestedTransaction()) { // Create savepoint within existing Spring-managed transaction, // through the SavepointManager API implemented by TransactionStatus. // Usually uses JDBC 3.0 savepoints. Never activates Spring synchronization. DefaultTransactionStatus status = prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null); //注意此處會(huì)創(chuàng)建savePoint status.createAndHoldSavepoint(); return status; } else { // Nested transaction through nested begin and commit/rollback calls. // Usually only for JTA: Spring synchronization might get activated here // in case of a pre-existing JTA transaction. boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER); // 注意此處newTransaction屬性設(shè)置為true,說(shuō)明確實(shí)采用了創(chuàng)建新事務(wù)方式來(lái)實(shí)現(xiàn) DefaultTransactionStatus status = newTransactionStatus( definition, transaction, true, newSynchronization, debugEnabled, null); doBegin(transaction, definition); prepareSynchronization(status, definition); return status; } } // Assumably PROPAGATION_SUPPORTS or PROPAGATION_REQUIRED. if (debugEnabled) { logger.debug("Participating in existing transaction"); } if (isValidateExistingTransaction()) { if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) { Integer currentIsolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel(); if (currentIsolationLevel == null || currentIsolationLevel != definition.getIsolationLevel()) { Constants isoConstants = DefaultTransactionDefinition.constants; throw new IllegalTransactionStateException("Participating transaction with definition [" + definition + "] specifies isolation level which is incompatible with existing transaction: " + (currentIsolationLevel != null ? isoConstants.toCode(currentIsolationLevel, DefaultTransactionDefinition.PREFIX_ISOLATION) : "(unknown)")); } } if (!definition.isReadOnly()) { if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) { throw new IllegalTransactionStateException("Participating transaction with definition [" + definition + "] is not marked as read-only but existing transaction is"); } } } boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER); // 其他的傳播特性則加入當(dāng)前事務(wù) 不會(huì)創(chuàng)建新事務(wù) return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null); }
可以看到,當(dāng)已經(jīng)存在事務(wù)時(shí),
- NEVER 直接報(bào)錯(cuò),不支持事務(wù)
- NOT_SUPPORTED 默默按照非事務(wù)方式運(yùn)行
- REQUIRES_NEW 新建一個(gè)事務(wù)。
- NESTED 處理嵌套事務(wù) 視情況采用savePoint或者新建事務(wù)。
- 其他的 加入當(dāng)前事務(wù)
四、NESTED 嵌套事務(wù)
SavePoint
先簡(jiǎn)單說(shuō)說(shuō)SavePoint機(jī)制吧。這個(gè)也比較簡(jiǎn)單。
比如一個(gè) 事務(wù)比較復(fù)雜,容易出錯(cuò)。那么如果當(dāng)前DB支持SavePoint的話,那么創(chuàng)建一個(gè)SavePoint就等于創(chuàng)建了一個(gè)快照,可以不用每次都回滾整個(gè)事務(wù),僅回滾到指定的SavePoint即可。
五、個(gè)人理解
NESTED這個(gè)處理確實(shí)比較復(fù)雜。個(gè)人也查了很多資料。目前個(gè)人目前理解如下:
NESTED對(duì)于事務(wù)的處理主要在于級(jí)別不同。
REQUIRES_NEW創(chuàng)建的兩個(gè)事務(wù)是平級(jí)的,一個(gè)事務(wù)的成功與否對(duì)另一個(gè)事務(wù)的成功與否不產(chǎn)生影響。
而NESTED創(chuàng)建的事務(wù)則名副其實(shí),是受其父級(jí)事務(wù)影響的。
一句話總結(jié)就是,子事務(wù)的成功與否不影響父級(jí)事務(wù)的成功,但是父級(jí)事務(wù)的成功與否則會(huì)影響子事務(wù)的成功。
父事務(wù)回滾,子事務(wù)一定會(huì)滾。
子事務(wù)回滾,父事務(wù)不一定會(huì)滾。
六、總結(jié)
最后總結(jié)如下
名稱 | 說(shuō)明 |
PROPAGATION_REQUIRED | 方法被調(diào)用時(shí)自動(dòng)開(kāi)啟事務(wù),在事務(wù)范圍內(nèi)使用則使用同一個(gè)事務(wù),否則開(kāi)啟新事務(wù)。 默認(rèn)選項(xiàng)。 |
PROPAGATION_SUPPORTS | 支持當(dāng)前事務(wù),如果當(dāng)前沒(méi)有事務(wù),就以非事務(wù)方式執(zhí)行。 |
PROPAGATION_MANDATORY | 支持當(dāng)前事務(wù),如果當(dāng)前沒(méi)有事務(wù),就拋出異常。 |
PROPAGATION_REQUIRES_NEW | 新建事務(wù),如果當(dāng)前存在事務(wù),把當(dāng)前事務(wù)掛起。 |
PROPAGATION_NOT_SUPPORTED | 以非事務(wù)方式執(zhí)行操作,如果當(dāng)前存在事務(wù),就把當(dāng)前事務(wù)掛起。 |
PROPAGATION_NEVER | 以非事務(wù)方式執(zhí)行,如果當(dāng)前存在事務(wù),則拋出異常。 |
PROPAGATION_NESTED | 如果一個(gè)活動(dòng)的事務(wù)存在,則運(yùn)行在一個(gè)嵌套的事務(wù)中. 如果沒(méi)有活動(dòng)事務(wù), 則按TransactionDefinition.PROPAGATION_REQUIRED 屬性執(zhí)行。需要JDBC3.0以上支持。 |
到此這篇關(guān)于Spring源碼解析之事務(wù)傳播特性的文章就介紹到這了,更多相關(guān)Spring事務(wù)傳播特性內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
一個(gè)applicationContext 加載錯(cuò)誤導(dǎo)致的阻塞問(wèn)題及解決方法
這篇文章主要介紹了一個(gè)applicationContext 加載錯(cuò)誤導(dǎo)致的阻塞問(wèn)題及解決方法,需要的朋友可以參考下2018-11-11Springboot整合freemarker 404問(wèn)題解決方案
這篇文章主要介紹了Springboot整合freemarker 404問(wèn)題解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-05-05Java 定時(shí)器(Timer)及線程池里使用定時(shí)器實(shí)例代碼
這篇文章主要介紹了Java 定時(shí)器(Timer)及線程池里使用定時(shí)器實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下2016-12-12Spring cloud gateway設(shè)置context-path服務(wù)路由404排查過(guò)程
這篇文章主要介紹了Spring cloud gateway設(shè)置context-path服務(wù)路由404排查過(guò)程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08Sentinel 整合SpringCloud的詳細(xì)教程
Spring Cloud Alibaba Sentinel 是阿里巴巴提供的,致力于提供微服務(wù)一站式解決方案,這篇文章主要介紹了Sentinel 之 整合SpringCloud的相關(guān)知識(shí),需要的朋友可以參考下2021-10-10