最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

spring事務(wù)之事務(wù)掛起和事務(wù)恢復(fù)源碼解讀

 更新時(shí)間:2022年11月21日 11:01:25   作者:小小少年_  
這篇文章主要介紹了spring事務(wù)之事務(wù)掛起和事務(wù)恢復(fù)源碼解讀,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

事務(wù)掛起和事務(wù)恢復(fù)源碼解讀

在學(xué)習(xí)spring事務(wù)的時(shí)候,一定會(huì)涉及到一個(gè)概念,無(wú)法避免的,就是事務(wù)掛起和事務(wù)恢復(fù)

對(duì)于事務(wù)掛起和事務(wù)恢復(fù),可以簡(jiǎn)單的描述一下,是這樣的

  • 1.首先我們假設(shè)有兩個(gè)類,A類和B類,兩個(gè)類中的字段是一模一樣的,A類表示當(dāng)前事務(wù),B類表示備份事務(wù)
  • 2.如果我開(kāi)啟一個(gè)事務(wù),會(huì)把當(dāng)前事務(wù)信息,存入到A類中,如果我這時(shí)候要進(jìn)行事務(wù)掛起
  • 3.事務(wù)掛起:就會(huì)把A類中當(dāng)前事務(wù)的信息,賦值到B類中,然后在創(chuàng)建一個(gè)新事務(wù)的時(shí)候,會(huì)賦值到A類中
  • 4.恢復(fù)事務(wù):如果此時(shí)我當(dāng)前事務(wù)執(zhí)行完畢了,需要恢復(fù)原來(lái)的事務(wù),就只需要將A類清空,然后將B類中的數(shù)據(jù)信息賦值到A類,此時(shí)A事務(wù)就會(huì)再次生效

我覺(jué)得可以理解為就是倒騰了一手

事務(wù)掛起源碼

org.springframework.transaction.support.AbstractPlatformTransactionManager#handleExistingTransaction

我們直接跳入到這個(gè)方法中來(lái)看,這個(gè)方法是在當(dāng)前事務(wù)存在的時(shí)候,會(huì)進(jìn)入到這個(gè)方法來(lái)處理,執(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

正常的話,一個(gè)事務(wù)方法的執(zhí)行是這個(gè)鏈路,自己debug看下即可,但是要進(jìn)入到這個(gè)方法中,有一個(gè)前提,就是當(dāng)前事務(wù)已存在,然后又調(diào)用了另外一個(gè)事務(wù)方法,才會(huì)進(jìn)入到這里

我們以PROPAGATION_REQUIRES_NEW這個(gè)級(jí)別的傳播機(jī)制為例,為什么以這個(gè)為例,因?yàn)檫@個(gè)傳播機(jī)制,在當(dāng)前事務(wù)存在的時(shí)候,是會(huì)將當(dāng)前事務(wù)掛起,然后開(kāi)啟一個(gè)新的事務(wù),也正好可以看下spring是如何掛起事務(wù),并創(chuàng)建新事務(wù)的

if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
	if (debugEnabled) {
		logger.debug("Suspending current transaction, creating new transaction with name [" +
				definition.getName() + "]");
	}
	/**
	 * 這里是掛起事務(wù)的操作,掛起事務(wù)的話,會(huì)把事務(wù)管理器中的屬性設(shè)置為null
	 * ,然后將事務(wù)管理器中的屬性暫時(shí)存儲(chǔ)到suspendedResourceHolder中
	 */
	SuspendedResourcesHolder suspendedResources = suspend(transaction);
	try {
		boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
		DefaultTransactionStatus status = newTransactionStatus(
				definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
		// 開(kāi)啟事務(wù)
		doBegin(transaction, definition);
		// 將事務(wù)綁定到線程中
		prepareSynchronization(status, definition);
		return status;
	}
	catch (RuntimeException | Error beginEx) {
		/**
		 * 如果在開(kāi)啟新的事務(wù)的時(shí)候,異常了,就會(huì)在下面這個(gè)方法中,將事務(wù)恢復(fù)(和上面掛起是相對(duì)的)
		 * ,其實(shí)就是把suspendResourceHolder中的屬性重新賦值到TransactionSynchronizationManager
		 */
		resumeAfterBeginException(transaction, suspendedResources, beginEx);
		throw beginEx;
	}
}

由于這個(gè)方法中,代碼比較多,我就刪減了一部分,只留下了propagation_requires_new這個(gè)傳播機(jī)制的代碼

可以看到,會(huì)先調(diào)用suspend(transaction)將當(dāng)前事務(wù)掛起,然后再下面的doBegin()再開(kāi)啟一個(gè)新的事務(wù),然后通過(guò)prepareSynchronization(),將事務(wù)相關(guān)信息放入到threadLocal中

suspend(transaction)

/**
* 這是掛起事務(wù)的源碼
 * 所謂的事務(wù)掛起:就是將當(dāng)前事務(wù)管理器中的相關(guān)屬性,保存到suspendedResourceHolder中
 */
@Nullable
protected final SuspendedResourcesHolder suspend(@Nullable Object transaction) throws TransactionException {
	/**
	 * 1.如果當(dāng)前事務(wù)是active狀態(tài),就將事務(wù)掛起,掛起的操作其實(shí)也簡(jiǎn)單
	 * 將當(dāng)前事務(wù)的屬性信息暫存到SuspendedResourcesHolder中,然后將當(dāng)前事務(wù)的屬性設(shè)置為null
	 */
	if (TransactionSynchronizationManager.isSynchronizationActive()) {
		List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization();
		try {
			Object suspendedResources = null;
			if (transaction != null) {
				suspendedResources = doSuspend(transaction);
			}
			/**
			 * 1.1 下面就是掛起事務(wù)的操作,將事務(wù)同步管理器中的屬性置為null
			 * , 然后將配置信息,存儲(chǔ)到suspendedResources中,以便在恢復(fù)事務(wù)的時(shí)候,可以恢復(fù)
			 */
			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.如果掛起事務(wù)失敗,就需要進(jìn)行回滾,就是將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這個(gè)注釋位置,會(huì)獲取到當(dāng)前事務(wù)的屬性信息,然后在下面,會(huì)new SuspendedResourcesHolder(),將當(dāng)前事務(wù)屬性信息放入到這里面

再下面,就是一些異常的判斷和處理,我們可以認(rèn)為,這個(gè)方法就是把事務(wù)的屬性信息存入到了SuspendedResourcesHolder對(duì)象中

newTransactionStatus()

這個(gè)方法也很重要,會(huì)把剛才創(chuàng)建的suspend對(duì)象,放入到DefaultTransactionStatus類中,這里我猜是為了在后面事務(wù)恢復(fù)的時(shí)候用的

doBegin()

在doBegin()方法中,主要是重新獲取一個(gè)數(shù)據(jù)庫(kù)連接,然后設(shè)置連接的相關(guān)信息,比如:非自動(dòng)提交等

然后將連接信息存入到TransactionSynchronizationManager對(duì)象中

我們可以簡(jiǎn)單認(rèn)為doBegin()就是重新開(kāi)啟了一個(gè)事務(wù)連接

事務(wù)恢復(fù)

前面講的是事務(wù)掛起,下面來(lái)說(shuō)事務(wù)恢復(fù),事務(wù)恢復(fù),就是在事務(wù)提交或者回滾的時(shí)候,會(huì)進(jìn)行事務(wù)恢復(fù)的處理


這里直接貼了一張圖,是事務(wù)提交和事務(wù)回滾的處理流程,最終都會(huì)調(diào)用到cleanupAfterCompletion()方法,這個(gè)方法就是事務(wù)恢復(fù)的代碼

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());
		}
	}

在這個(gè)代碼中,前面是一些邏輯處理,應(yīng)該是對(duì)當(dāng)前事務(wù)進(jìn)行清除的操作,需要關(guān)注的是最后一行代碼,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是哪個(gè)對(duì)象呢?

就是前面事務(wù)掛起的時(shí)候,將當(dāng)前事務(wù)參數(shù)信息賦值到的一個(gè)對(duì)象

所以

我們可以認(rèn)為,事務(wù)掛起就是將事務(wù)賦值到一個(gè)臨時(shí)對(duì)象中,事務(wù)恢復(fù)就是從臨時(shí)對(duì)象中,將事務(wù)屬性信息賦值到當(dāng)前事務(wù)中

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 基于Java制作一個(gè)燈謎猜猜樂(lè)游戲

    基于Java制作一個(gè)燈謎猜猜樂(lè)游戲

    中秋佳節(jié),是我國(guó)傳統(tǒng)的重大節(jié)日之一,全國(guó)各地為了增強(qiáng)過(guò)節(jié)的氣氛,都有許多傳統(tǒng)的中秋活動(dòng),比如猜燈謎,所以本文就來(lái)用Java制作一個(gè)燈謎猜猜樂(lè)游戲,感興趣的可以了解下
    2023-09-09
  • java構(gòu)造方法的作用總結(jié)

    java構(gòu)造方法的作用總結(jié)

    在本篇文章里小編給大家整理了關(guān)于java構(gòu)造方法的相關(guān)知識(shí)點(diǎn)以及實(shí)例代碼,有需要的朋友們可以學(xué)習(xí)下。
    2019-07-07
  • Spring Security動(dòng)態(tài)權(quán)限的實(shí)現(xiàn)方法詳解

    Spring Security動(dòng)態(tài)權(quán)限的實(shí)現(xiàn)方法詳解

    這篇文章主要和小伙伴們簡(jiǎn)單介紹下 Spring Security 中的動(dòng)態(tài)權(quán)限方案,以便于小伙伴們更好的理解 TienChin 項(xiàng)目中的權(quán)限方案,感興趣的可以了解一下
    2022-06-06
  • Java中獲取年份月份的幾種常見(jiàn)方法

    Java中獲取年份月份的幾種常見(jiàn)方法

    這篇文章主要給大家介紹了關(guān)于Java中獲取年份月份的幾種常見(jiàn)方法,在開(kāi)發(fā)應(yīng)用程序時(shí),經(jīng)常需要獲取當(dāng)前的年、月、日,并以特定格式進(jìn)行展示或處理,需要的朋友可以參考下
    2023-09-09
  • Springboot應(yīng)用gradle?Plugin示例詳解

    Springboot應(yīng)用gradle?Plugin示例詳解

    這篇文章主要介紹了Springboot應(yīng)用gradle?Plugin詳解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-04-04
  • Scala入門(mén)教程詳解

    Scala入門(mén)教程詳解

    這篇文章主要介紹了Scala入門(mén)教程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06
  • springboot中關(guān)于自動(dòng)建表,無(wú)法更新字段的問(wèn)題

    springboot中關(guān)于自動(dòng)建表,無(wú)法更新字段的問(wèn)題

    這篇文章主要介紹了springboot中關(guān)于自動(dòng)建表,無(wú)法更新字段的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • Java實(shí)現(xiàn)用戶管理系統(tǒng)

    Java實(shí)現(xiàn)用戶管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)用戶管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • springboot項(xiàng)目部署到寶塔的詳細(xì)圖文教程

    springboot項(xiàng)目部署到寶塔的詳細(xì)圖文教程

    網(wǎng)上關(guān)于寶塔運(yùn)行springBoot的東西說(shuō)有點(diǎn)迷糊,但是有一句話很重要,Spring boot項(xiàng)目只需要JDK環(huán)境即可部署成功,下面這篇文章主要給大家介紹了關(guān)于springboot項(xiàng)目部署到寶塔的詳細(xì)圖文教程,需要的朋友可以參考下
    2023-05-05
  • Java二叉樹(shù)的四種遍歷(遞歸和非遞歸)

    Java二叉樹(shù)的四種遍歷(遞歸和非遞歸)

    這篇文章主要介紹了Java二叉樹(shù)的四種遍歷,二叉樹(shù)的遍歷可以分為前序、中序、后序、層次遍歷,需要的朋友可以參考下
    2020-12-12

最新評(píng)論

锦州市| 天津市| 登封市| 桦南县| 盘山县| 满洲里市| 潮安县| 从化市| 石门县| 蒲城县| 乌鲁木齐市| 宜宾市| 长葛市| 苗栗市| 十堰市| 图们市| 泰顺县| 新巴尔虎右旗| 克东县| 富民县| 鄂托克前旗| 玉屏| 会东县| 丹东市| 湘阴县| 吴堡县| 神农架林区| 响水县| 香港 | 临夏市| 绿春县| 安徽省| 溆浦县| 东乡族自治县| 宝山区| 三穗县| 巴楚县| 买车| 区。| 孟村| 靖州|