偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

事務(wù)中存在多線程,怎么處理?

開發(fā) 前端
Spring 管理的事務(wù)上下文是基于調(diào)用線程的,新線程并沒有繼承原線程的 TransactionSynchronizationManager 中的事務(wù)上下文。因此,新線程執(zhí)行的數(shù)據(jù)庫(kù)操作實(shí)際上是在無(wú)事務(wù)管理的環(huán)境下進(jìn)行的,這就導(dǎo)致事務(wù)失效。

在 Spring 框架中,@Transactional 注解作為一種聲明式事務(wù)管理的關(guān)鍵機(jī)制,其背后的工作原理遠(yuǎn)比簡(jiǎn)單的 AOP(面向切面編程)和 ThreadLocal 存儲(chǔ)更為細(xì)膩。該注解的實(shí)現(xiàn)核心在于 Spring 的 TransactionInterceptor(事務(wù)攔截器)以及它如何與 Spring 的代理機(jī)制、TransactionManager(事務(wù)管理器)協(xié)同工作,來確保事務(wù)的開啟、提交或回滾等操作得以正確執(zhí)行。

一 注解解析與代理生成

當(dāng) Spring 容器初始化時(shí),會(huì)通過 AnnotationTransactionAttributeSource 掃描并識(shí)別出所有標(biāo)有 @Transactional 的方法。這些方法在被調(diào)用前,Spring 會(huì)根據(jù)配置(如基于接口或類的代理)為它們創(chuàng)建動(dòng)態(tài)代理對(duì)象。如果是基于接口的代理,則使用 JDK Dynamic Proxy;如果是基于類的,則采用 CGLIB。這個(gè)代理對(duì)象會(huì)在目標(biāo)方法調(diào)用前后插入事務(wù)處理邏輯。

1.1 Spring Bean的后處理器

一切始于 Spring 容器的 Bean 創(chuàng)建和初始化過程。Spring 通過一系列的 BeanPostProcessor 接口實(shí)現(xiàn)類來增強(qiáng) Bean 的功能,其中與事務(wù)管理密切相關(guān)的便是 AbstractAutoProxyCreator的子類,如 AnnotationAwareAspectJAutoProxyCreator。這個(gè)類負(fù)責(zé)掃描并創(chuàng)建代理對(duì)象,以便于在運(yùn)行時(shí)織入諸如事務(wù)管理這樣的切面邏輯。

1.2 識(shí)別 @Transactional 注解

  • ClassPathScanningCandidateComponentProvider:Spring 首先會(huì)使用此類掃描指定包路徑下帶有特定注解(如@Transactional)的類或方法。
  • AnnotationTransactionAttributeSource:一旦找到帶有 @Transactional 注解的類或方法,Spring 會(huì)使用 AnnotationTransactionAttributeSource 來解析這些注解,將其轉(zhuǎn)換為事務(wù)屬性(TransactionAttribute),比如事務(wù)的隔離級(jí)別、傳播行為、超時(shí)時(shí)間等。

1.3 創(chuàng)建代理對(duì)象

  • 對(duì)于基于接口的代理,Spring 使用 JDK 的動(dòng)態(tài)代理技術(shù),通過JdkDynamicAopProxy創(chuàng)建代理對(duì)象。該代理會(huì)檢查調(diào)用鏈,并在調(diào)用目標(biāo)方法前插入事務(wù)管理的前置邏輯,調(diào)用后插入后置邏輯(如提交或回滾事務(wù))。
  • 對(duì)于沒有實(shí)現(xiàn)接口的類,Spring 則利用 CGLIB 庫(kù)生成目標(biāo)類的子類作為代理,通過CglibAopProxy 來完成。CGLIB 代理同樣能夠在目標(biāo)方法調(diào)用的前后插入事務(wù)管理代碼。

1.4 TransactionInterceptor

  • 在代理對(duì)象中,事務(wù)管理的具體邏輯是由 TransactionInterceptor(事務(wù)攔截器)來執(zhí)行的。它實(shí)現(xiàn)了 MethodInterceptor 接口,因此當(dāng)代理對(duì)象的方法被調(diào)用時(shí),會(huì)進(jìn)入invoke(MethodInvocation invocation) 方法。在這個(gè)方法內(nèi),TransactionInterceptor 根據(jù)解析出的事務(wù)屬性來決定是否開啟事務(wù)、使用何種傳播行為,并最終調(diào)用目標(biāo)方法。

總結(jié)下就是,Spring 通過 Bean 的后置處理器在容器初始化階段自動(dòng)檢測(cè)帶有 @Transactional 注解的類和方法,并通過動(dòng)態(tài)代理機(jī)制為這些組件創(chuàng)建代理對(duì)象。代理對(duì)象在方法調(diào)用時(shí),通過 TransactionInterceptor 這一核心組件,根據(jù)注解配置的事務(wù)屬性來管理事務(wù)生命周期,確保事務(wù)邏輯的無(wú)縫集成。

二 事務(wù)攔截與執(zhí)行

2.1 TransactionInterceptor 的作用

TransactionInterceptor 實(shí)現(xiàn)了 Spring 的 MethodInterceptor 接口,這意味著它能夠攔截方法調(diào)用,并在調(diào)用前后執(zhí)行額外的邏輯,即事務(wù)管理邏輯。其核心職責(zé)包括:

  • 識(shí)別是否需要事務(wù): 根據(jù)目標(biāo)方法上的 @Transactional 注解(如果有的話)及其屬性(如傳播行為、隔離級(jí)別、超時(shí)時(shí)間等),決定是否需要啟動(dòng)一個(gè)新的事務(wù)或加入到現(xiàn)有的事務(wù)中。需要注意的是,事務(wù)上下文(包括連接信息等)被存儲(chǔ)在由 Spring 管理的一個(gè)特定的 TransactionSynchronizationManager 中,TransactionSynchronizationManager 內(nèi)部使用了 ThreadLocal。
  • 事務(wù)管理: 在方法調(diào)用之前開啟事務(wù),調(diào)用之后根據(jù)方法執(zhí)行結(jié)果提交或回滾事務(wù)。這包括異常處理邏輯,即在遇到未被捕獲的異常時(shí),確保事務(wù)被正確回滾。

2.2 攔截與執(zhí)行流程

  1. 方法調(diào)用前:
  • 事務(wù)屬性解析: TransactionInterceptor 首先通過TransactionAttributeSource(通常是AnnotationTransactionAttributeSource)獲取目標(biāo)方法的事務(wù)屬性。
  • 事務(wù)開始: 根據(jù)解析出的事務(wù)屬性,決定是否創(chuàng)建新的事務(wù)或者加入到當(dāng)前事務(wù)中。如果需要新事務(wù),它會(huì)通過事務(wù)管理器(如 PlatformTransactionManager 的實(shí)現(xiàn)類)來開始事務(wù)。
  1. 方法執(zhí)行:
  • 在事務(wù)上下文中執(zhí)行實(shí)際的目標(biāo)方法。此時(shí),如果目標(biāo)方法內(nèi)部拋出了異常,這個(gè)異常會(huì)被暫存以供后續(xù)處理。

  1. 方法調(diào)用后:

  • 異常處理: 如果方法執(zhí)行過程中拋出了異常,TransactionInterceptor 會(huì)捕獲到這個(gè)異常,并根據(jù)異常類型及事務(wù)屬性決定是否需要回滾事務(wù)。通常,非檢查型異常(繼承自 RuntimeException 的異常)會(huì)導(dǎo)致事務(wù)回滾,而檢查型異常則不會(huì),除非事務(wù)屬性特別指定了回滾規(guī)則。

  • 事務(wù)提交或回滾: 如果方法正常結(jié)束,或者按事務(wù)屬性應(yīng)該提交事務(wù)的情況下,事務(wù)管理器會(huì)提交事務(wù)。相反,如果需要回滾,則執(zhí)行回滾操作。

  1. 資源清理: 在事務(wù)結(jié)束后,確保所有資源被正確釋放,比如關(guān)閉數(shù)據(jù)庫(kù)連接等。

2.3 動(dòng)態(tài)代理的作用

整個(gè)過程中,動(dòng)態(tài)代理扮演著關(guān)鍵角色。無(wú)論是 JDK 動(dòng)態(tài)代理還是 CGLIB 代理,它們都是在調(diào)用真正業(yè)務(wù)方法之前插入事務(wù)攔截邏輯的橋梁。當(dāng)客戶端代碼調(diào)用代理對(duì)象上的方法時(shí),實(shí)際上是調(diào)用了由 TransactionInterceptor 所控制的代理邏輯,從而透明地在業(yè)務(wù)邏輯執(zhí)行前后管理事務(wù)。

通過這種方式,開發(fā)者無(wú)需在每個(gè)需要事務(wù)管理的方法中手動(dòng)編寫開啟、提交或回滾事務(wù)的代碼,極大地簡(jiǎn)化了開發(fā)復(fù)雜度,提高了代碼的可維護(hù)性和可讀性。

三 多線程環(huán)境下的挑戰(zhàn)

當(dāng) @Transactional 標(biāo)記的方法內(nèi)部啟動(dòng)新的線程時(shí),問題就顯現(xiàn)了。前面提到,事務(wù)攔截使用了 TransactionInterceptor,而 TransactionInterceptor 內(nèi)部用到了  TransactionSynchronizationManager,TransactionSynchronizationManager 使用 ThreadLocal 來存儲(chǔ)事務(wù)相關(guān)的資源信息,如數(shù)據(jù)庫(kù)連接、JMS 會(huì)話等。這意味著每個(gè)線程都有其獨(dú)立的事務(wù)上下文,確保了事務(wù)信息在線程間的隔離。

換句話說,Spring 管理的事務(wù)上下文是基于調(diào)用線程的,新線程并沒有繼承原線程的 TransactionSynchronizationManager 中的事務(wù)上下文。因此,新線程執(zhí)行的數(shù)據(jù)庫(kù)操作實(shí)際上是在無(wú)事務(wù)管理的環(huán)境下進(jìn)行的,這就導(dǎo)致事務(wù)失效。

那如果非要用多線程怎么辦呢?這個(gè)時(shí)候可以使用編程式事務(wù),首先設(shè)置一個(gè)全局變量 Boolean,默認(rèn)是可以提交的 true,在子線程,通過編程式事務(wù)的方式去開啟事務(wù),然后插入數(shù)據(jù),插入完成后,事務(wù)先不提交,同時(shí)通知主線程,我準(zhǔn)備好了,進(jìn)入等待狀態(tài)。如果子線程出現(xiàn)異常,那就通知主線程,我這邊發(fā)生異常,然后自己回滾。

最后主線程收集各個(gè)子線程的狀態(tài),如果有一個(gè)線程出現(xiàn)問題,那么全局變量就設(shè)置為不可提交false,然后喚醒所有子線程,進(jìn)行回滾。

這里涉及到線程同步可以利用閉鎖去實(shí)現(xiàn);當(dāng)主線程通知各個(gè)子線程提交事務(wù)的時(shí)候,子線程可能在提交的時(shí)候出錯(cuò)了,最終導(dǎo)致數(shù)據(jù)不一致,那么這種時(shí)候可能就需要引入重試機(jī)制,有了重試機(jī)制后,又要去保證冪等性等等。

這一套方案下來大伙有沒有覺得眼熟,是不是就是分布式事務(wù)的處理思路了?

所以說,非要在事務(wù)中開啟多線程也沒問題,但是不建議這么做。

責(zé)任編輯:武曉燕 來源: 江南一點(diǎn)雨
相關(guān)推薦

2022-05-20 10:20:17

Spring事務(wù)MyBatis

2024-04-30 12:56:00

多線程.NET

2015-11-18 18:56:36

Java多線程處理

2020-05-14 09:31:48

Python多處理多線程

2020-04-29 09:10:26

Python多線程多處理

2024-09-26 10:51:51

2024-10-18 16:58:26

2021-06-29 07:47:23

多線程協(xié)作數(shù)據(jù)

2025-06-25 06:18:46

Linux多線程機(jī)制

2010-04-14 09:20:26

.NET多線程

2011-06-13 10:03:19

Qt 多線程 編程

2010-03-17 09:33:30

Java多線程方案

2009-03-12 10:52:43

Java線程多線程

2013-12-02 17:33:20

Linux進(jìn)程多線程

2011-06-30 17:31:32

Qt 多線程 信號(hào)

2023-05-12 14:14:00

Java線程中斷

2022-03-04 10:17:04

Redis數(shù)據(jù)

2021-03-26 05:54:00

C#數(shù)據(jù)方法

2021-06-10 00:13:43

C#隊(duì)列數(shù)據(jù)

2010-03-16 14:20:57

Java多線程調(diào)試
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)