溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Spring中事務(wù)傳播特性的示例分析

發(fā)布時間:2021-05-28 09:36:14 來源:億速云 閱讀:157 作者:小新 欄目:開發(fā)技術(shù)

這篇文章主要介紹Spring中事務(wù)傳播特性的示例分析,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!

一、使用方式

可以采用Transactional,配置propagation即可。
打開org.springframework.transaction.annotation.Transactional可見默認(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

顧名思義,此項屬性是在事務(wù)存在交互時生效。那么到底是如何生效的呢,核心源碼位于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ù)傳播特性進行處理
		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則會新建一個事務(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ù)時,

  • MANDATORY 直接拋出異常

  • REQUIRED REQUIRES_NEW NESTED 自動新建一個事務(wù)。

那么存在事務(wù)時是如何處理的呢?

三、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ù)為null,所以是采用非事務(wù)方式運行。執(zhí)行會掛起當(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ù) 會掛起當(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 否則開啟新事務(wù) 并不會掛起當(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);
				//注意此處會創(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,說明確實采用了創(chuàng)建新事務(wù)方式來實現(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ù) 不會創(chuàng)建新事務(wù)
		return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
	}

可以看到,當(dāng)已經(jīng)存在事務(wù)時,

  • NEVER 直接報錯,不支持事務(wù)

  • NOT_SUPPORTED 默默按照非事務(wù)方式運行

  • REQUIRES_NEW 新建一個事務(wù)。

  • NESTED 處理嵌套事務(wù) 視情況采用savePoint或者新建事務(wù)。

  • 其他的 加入當(dāng)前事務(wù)

四、NESTED 嵌套事務(wù)

SavePoint

先簡單說說SavePoint機制吧。這個也比較簡單。
比如一個 事務(wù)比較復(fù)雜,容易出錯。那么如果當(dāng)前DB支持SavePoint的話,那么創(chuàng)建一個SavePoint就等于創(chuàng)建了一個快照,可以不用每次都回滾整個事務(wù),僅回滾到指定的SavePoint即可。

五、個人理解

NESTED這個處理確實比較復(fù)雜。個人也查了很多資料。目前個人目前理解如下:
NESTED對于事務(wù)的處理主要在于級別不同。
REQUIRES_NEW創(chuàng)建的兩個事務(wù)是平級的,一個事務(wù)的成功與否對另一個事務(wù)的成功與否不產(chǎn)生影響。
而NESTED創(chuàng)建的事務(wù)則名副其實,是受其父級事務(wù)影響的。
一句話總結(jié)就是,子事務(wù)的成功與否不影響父級事務(wù)的成功,但是父級事務(wù)的成功與否則會影響子事務(wù)的成功。
父事務(wù)回滾,子事務(wù)一定會滾。
子事務(wù)回滾,父事務(wù)不一定會滾。

六、總結(jié)

最后總結(jié)如下

名稱說明
PROPAGATION_REQUIRED方法被調(diào)用時自動開啟事務(wù),在事務(wù)范圍內(nèi)使用則使用同一個事務(wù),否則開啟新事務(wù)。 默認(rèn)選項。
PROPAGATION_SUPPORTS支持當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù),就以非事務(wù)方式執(zhí)行。
PROPAGATION_MANDATORY支持當(dāng)前事務(wù),如果當(dāng)前沒有事務(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如果一個活動的事務(wù)存在,則運行在一個嵌套的事務(wù)中. 如果沒有活動事務(wù), 則按TransactionDefinition.PROPAGATION_REQUIRED 屬性執(zhí)行。需要JDBC3.0以上支持。

以上是“Spring中事務(wù)傳播特性的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對大家有幫助,更多相關(guān)知識,歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI