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

多線程下的事務(wù)失效及解決方案

 更新時間:2025年05月13日 09:03:51   作者:找不到、了  
這篇文章主要介紹了多線程下的事務(wù)失效及解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

使用 DataSourceTransactionManager 是在 Spring 框架中進行數(shù)據(jù)庫事務(wù)管理的一種常見方式。

它提供了一種簡便的方式來處理事務(wù),并能夠有效地解決多線程環(huán)境下的事務(wù)隔離和一致性問題。

單核cpu的多線程模型圖如下所示:

從上述模型可以知道,線程1、線程2會因為cpu的來回切換,導(dǎo)致當(dāng)前事務(wù)的上下文不同,因此處于失效狀態(tài)。

1、定義

多線程和并發(fā)是計算機科學(xué)中與執(zhí)行多個任務(wù)相關(guān)的兩個重要概念。

盡管它們在某些方面密切相關(guān),但它們代表了不同的概念,下面是它們之間的主要區(qū)別和聯(lián)系。

1.1、多線程

多線程是指在一個進程中同時運行多個線程。每個線程有自己的執(zhí)行路徑,可以在共享的內(nèi)存空間中執(zhí)行,也可以共享進程的資源。

如下圖所示:

多線程的一個主要目標(biāo)是利用多核 CPU 的能力,以提高程序的并行性和響應(yīng)速度。

1.2、并發(fā)

    并發(fā)是指兩個或多個任務(wù)或進程在同一時間段內(nèi)進行處理,通常是通過多個線程、進程或任務(wù)的交替執(zhí)行來實現(xiàn)。

    如下圖所示:

    并發(fā)不一定指真正的同時運行,它可能是通過快速切換來模擬同時運行的效果。并發(fā)可以在單線程或多線程環(huán)境中實現(xiàn),只要在時間上有重疊即可。

    2、多線程事務(wù)

    多線程事務(wù)和單線程事務(wù)是兩種對事務(wù)處理的不同實現(xiàn)方式,特別是在涉及數(shù)據(jù)庫和并發(fā)操作的場景中。

    2.1、定義

    單線程事務(wù)

    • 在單線程環(huán)境中,事務(wù)在一個線程中完成,沒有其他線程的干擾。
    • 所有的操作順序執(zhí)行,事務(wù)的開始、提交和回滾都在同一個線程中處理。

    多線程事務(wù)

    • 在多線程環(huán)境中,多個線程可以訪問和操作同一事務(wù)。可能會有多個線程并發(fā)執(zhí)行的事務(wù),或同一事務(wù)在不同線程中交替進行。
    • 這種方式更復(fù)雜,因為需要考慮多個線程對共享數(shù)據(jù)的競爭、隔離和一致性。

    2.2、主要區(qū)別

    并發(fā)性

    • 單線程事務(wù):操作是線性的,只有一個線程在執(zhí)行事務(wù),與其他事務(wù)完全隔離。通常更容易實現(xiàn)和維護。
    • 多線程事務(wù):事務(wù)的并發(fā)處理可能導(dǎo)致數(shù)據(jù)競爭,多個線程可能同時讀取和寫入相同的數(shù)據(jù),導(dǎo)致數(shù)據(jù)的不一致性。

    數(shù)據(jù)一致性

    • 單線程事務(wù):由于沒有其他線程參與,數(shù)據(jù)一致性容易維護。只要在事務(wù)中完成的操作是原子性的,就能保證一致性。
    • 多線程事務(wù):需依賴事務(wù)隔離級別來保證一致性,例如讀已提交、可重復(fù)讀,以及串行化等。必須采用鎖或其他機制來處理并發(fā)沖突。

    鎖的使用

    • 單線程事務(wù):通常不會涉及復(fù)雜的鎖管理。
    • 多線程事務(wù):需要使用鎖或其他并發(fā)控制機制(如樂觀鎖、悲觀鎖)來處理數(shù)據(jù)競爭,提高系統(tǒng)的并發(fā)性,同時減少沖突。

    性能

    • 單線程事務(wù):性能簡單易測,因為沒有其他操作對于事務(wù)的直接影響。
    • 多線程事務(wù):性能會受到并發(fā)訪問的影響,需要考慮鎖的爭用和等待時間,以及如何平衡事務(wù)的執(zhí)行效率。

    2.3、聯(lián)系

    事務(wù)的性質(zhì)

    • 無論是單線程還是多線程,事務(wù)均有原子性、一致性、隔離性和持久性(ACID)屬性。
    • 這些屬性是保證數(shù)據(jù)正確性和完整性的重要原則。

    使用的技術(shù)

    • 兩者都可以應(yīng)用于數(shù)據(jù)庫系統(tǒng)中,無論是在單用戶環(huán)境還是多用戶環(huán)境,確保數(shù)據(jù)的完整性和一致性。

    設(shè)計考慮

    • 設(shè)計事務(wù)時,單線程和多線程的事務(wù)處理都需要考慮數(shù)據(jù)的一致性和隔離性。
    • 雖然實現(xiàn)細(xì)節(jié)不同,但在設(shè)計原則上是相通的。

    2.4、DataSourceTransactionManager

    實現(xiàn)了 PlatformTransactionManager 接口,主要用于基于 JDBC 的數(shù)據(jù)源事務(wù)管理。

    通過它可以控制事務(wù)的邊界,例如開始事務(wù)、提交事務(wù)和回滾事務(wù)。這種方式非常適合于多線程環(huán)境下的數(shù)據(jù)庫操作。

    2.5、TransactionSynchronizationManager

    是 Spring 框架的一部分,專門用于管理與事務(wù)相關(guān)的同步任務(wù)。

    它通常用于將事務(wù)資源與當(dāng)前線程綁定,使得在當(dāng)前線程中的所有操作都可以共享相同的事務(wù)上下文。

    在使用時,TransactionSynchronizationManager 經(jīng)常與數(shù)據(jù)源管理器(如 DataSourceTransactionManager)結(jié)合使用。使用 TransactionSynchronizationManager 綁定當(dāng)前線程

    TransactionSynchronizationManager 的主要用途是確保在當(dāng)前線程中執(zhí)行的所有數(shù)據(jù)庫操作都可以利用同一個事務(wù)。利用它可以將事務(wù)上下文與當(dāng)前線程捆綁在一起。

    代碼如下圖所示:

    public void bindResource(Object key, Object value) throws IllegalStateException {
            Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
            Assert.notNull(value, "Value must not be null");
            Map<Object, Object> map = this.transactionContext.getResources();
            Object oldValue = map.put(actualKey, value);
            if (oldValue != null) {
                throw new IllegalStateException("Already value [" + oldValue + "] for key [" + actualKey + "] bound to context [" + this.transactionContext.getName() + "]");
            } else {
                if (logger.isTraceEnabled()) {
                    logger.trace("Bound value [" + value + "] for key [" + actualKey + "] to context [" + this.transactionContext.getName() + "]");
                }
    
            }
        }

    3、事務(wù)處理

    事務(wù)處理分為編程式和聲明式兩種。

    3.1、底層原理

    當(dāng)目標(biāo)類被spring管理時(即@Component,@Service,@controller,@Repository注解時),spring會為目標(biāo)對象創(chuàng)建一個代理對象。代理對象負(fù)責(zé)攔截目標(biāo)方法的調(diào)用,并在必要時應(yīng)用事務(wù)管理(AOP思想)。

    代理對象內(nèi)部包含一個事務(wù)攔截器TransactionInterceptor,負(fù)責(zé)處理事務(wù)相關(guān)的邏輯。

    事務(wù)攔截器會檢查方法上是否添加了@Transactional注解,來決定是否應(yīng)用事務(wù)(JDBC的connection調(diào)用setAutoCommit(false),然后會將connection存到ThreadLocal(本地線程)中,

    (為了嵌套方法可以拿到外層事務(wù)的connection對象,只有使用同一個connection對象才能保證使用同一個事物)

    然后去執(zhí)行方法,從而執(zhí)行數(shù)據(jù)庫操作,然后再執(zhí)行嵌套方法,然后再嵌套方法的代理對象,就可以拿到外層事務(wù)的Thread Local中connection對象,從而執(zhí)行方法,嵌套方法發(fā)現(xiàn)ThreadLocal中有值,他不會提交事務(wù),而是統(tǒng)一的交給外層事務(wù)進行提交)

    事務(wù)攔截器在目標(biāo)方法執(zhí)行前后應(yīng)用事務(wù)通知,(前置通知和后置通知)在方法執(zhí)行前,事務(wù)攔截器啟動事務(wù);

    在方法執(zhí)行后,根據(jù)方法的執(zhí)行結(jié)果決定事務(wù)的提交或回滾。

    關(guān)于更多詳細(xì)了解,可參考:如何合理使用Spring的事務(wù)

    如下圖所示:

    3.2、失效原因

    如果在方法中開啟新線程去調(diào)用嵌套方法時,這時嵌套線程就拿不到外層事務(wù)的ThreadLocal中的connection對象。

    關(guān)于ThreadLocal是綁定在主線程上的。

    所以在新的線程中去調(diào)用嵌套方法時,就拿不到外層事務(wù)的connection對象,然后就會自己新建一個事務(wù),自己存一個connection到自己的ThreadLocal中,

    這樣的話,方法和嵌套方法就各開啟了一個事務(wù),且是同級事務(wù),相互不影響。

    但是這樣在外層事務(wù)失敗回滾的時候,內(nèi)層事務(wù)不受外層事務(wù)的影響,不進行回滾的話,就會造成事務(wù)回滾但還是寫入數(shù)據(jù)庫中的現(xiàn)象,我們要保證數(shù)據(jù)庫數(shù)據(jù)的一致性!

    3.3、解決方案

    1、使用TransactionSynchronizationManager

    在創(chuàng)建一個異步線程之后,可以手動的往嵌套方法的Tread Local中將外層事務(wù)connection對象存入,那么嵌套方法就可以從自己的Thread Local中拿到外層事務(wù)的connection了,這樣方法和嵌套方法用的就是同一個事務(wù)了。

    這樣就不會出現(xiàn)多線程事務(wù)失效的情況了。

    擴展:

    編程式事務(wù)中DataSourceTransactionManager類org.springframework.jdbc.datasource.DataSourceTransactionManager中的doBegin方法就是spring底層在開啟事務(wù)的時候進行調(diào)用的,在方法中獲取數(shù)據(jù)庫連接,并開啟事務(wù)。

    因此如果想要獲取對應(yīng)的connection,可以調(diào)用事務(wù)同步管理器的getResource()方法,

    將spring容器當(dāng)中的datasource傳進來,就可以拿到,

    然后再調(diào)用BindResource方法就可以將異步線程中的ThreadLocal中存入外層事務(wù)的connection。

    解決方案代碼展示:

     private DataSource datasource;
     ConnectionHolder connectionHolder = (ConnectionHolder)TransactionSynchronizedManager.getResource(dataSource);
     new Thread(()->{
     //綁定主線程的connection到子線程中
     TransactionSynchronizedManager.bindResource(dataSource,connectionHolder);
     //調(diào)用方法
     })

    2、join() 方法

    核心代碼示例:

    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    
    public class TransferExample {
        public static void main(String[] args) {
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
            TransferService transferService = context.getBean(TransferService.class);
    
            // 使用線程數(shù)組來存儲線程
            Thread[] threads = new Thread[3];
    
            // 創(chuàng)建多個線程來執(zhí)行轉(zhuǎn)賬
            for (int i = 0; i < threads.length; i++) {
                String fromAccount = "accountA";  // 設(shè)定轉(zhuǎn)賬來源賬戶
                String toAccount = "accountB";      // 設(shè)定轉(zhuǎn)賬目標(biāo)賬戶
                double amount = 100.0 * (i + 1);   // 每個線程按順序轉(zhuǎn)賬不同金額
    
                threads[i] = new Thread(() -> {
                    try {
                        transferService.transfer(fromAccount, toAccount, amount);
                        System.out.println("Transfer of " + amount + " from " + fromAccount + " to " + toAccount + " completed.");
                    } catch (Exception e) {
                        System.out.println("Transfer failed: " + e.getMessage());
                    }
                });
    
                threads[i].start();  // 啟動線程
            }
    
            // 等待所有線程完成
            for (Thread thread : threads) {
                try {
                    thread.join();  // 等待每個子線程完成
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
            context.close();
        }
    }

    通過適當(dāng)?shù)氖聞?wù)管理和使用 join() 方法等待子線程,然后將所有操作放在各自的事務(wù)中,這樣能夠確保數(shù)據(jù)的一致性和完整性。

    總結(jié)

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

    相關(guān)文章

    • Java調(diào)用Windows的DOS命令的方法

      Java調(diào)用Windows的DOS命令的方法

      這篇文章主要介紹了Java調(diào)用Windows的DOS命令的方法,其主要內(nèi)容思路是實現(xiàn)調(diào)用Windows的ipconfig命令,然后將輸出的信息通過IO流輸出到控制臺。有需要的小伙伴參考下
      2015-02-02
    • Javafx實現(xiàn)國際象棋游戲

      Javafx實現(xiàn)國際象棋游戲

      這篇文章主要為大家詳細(xì)介紹了Javafx實現(xiàn)國際象棋游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
      2019-05-05
    • MyBatis核心概念?+?環(huán)境搭建?+?CRUD實戰(zhàn)詳解

      MyBatis核心概念?+?環(huán)境搭建?+?CRUD實戰(zhàn)詳解

      文章主要介紹了MyBatis的核心知識,從JDBC痛點開始,闡述了MyBatis的優(yōu)勢,包括連接池管理、SQL與Java代碼解耦、自動結(jié)果集映射、參數(shù)自動映射等,感興趣的朋友跟隨小編一起看看吧
      2026-05-05
    • Java面試題沖刺第十三天--數(shù)據(jù)庫(3)

      Java面試題沖刺第十三天--數(shù)據(jù)庫(3)

      這篇文章主要為大家分享了最有價值的三道數(shù)據(jù)庫面試題,涵蓋內(nèi)容全面,包括數(shù)據(jù)結(jié)構(gòu)和算法相關(guān)的題目、經(jīng)典面試編程題等,感興趣的小伙伴們可以參考一下
      2021-07-07
    • 淺談Java四種線程池及new Thread的弊端

      淺談Java四種線程池及new Thread的弊端

      本文主要介紹了淺談Java四種線程池及new Thread的弊端,詳細(xì)的介紹了newCachedThreadPool,newFixedThreadPool,newScheduledThreadPool,newSingleThreadExecutor四種的使用,感興趣的可以了解一下
      2024-01-01
    • Spring源碼解析之BeanPostProcessor知識總結(jié)

      Spring源碼解析之BeanPostProcessor知識總結(jié)

      今天給大家?guī)淼奈恼率荢pring的相關(guān)知識,文章圍繞著BeanPostProcessor的使用展開,文中有非常詳細(xì)的介紹,需要的朋友可以參考下
      2021-06-06
    • Spring Security的持久化用戶和授權(quán)實現(xiàn)方式

      Spring Security的持久化用戶和授權(quán)實現(xiàn)方式

      文章介紹了如何使用JdbcUserDetailsManager實現(xiàn)數(shù)據(jù)庫讀取用戶,并展示了如何配置SpringSecurity進行授權(quán)管理,通過創(chuàng)建數(shù)據(jù)庫表、配置數(shù)據(jù)庫連接和修改SecurityConfig,實現(xiàn)了用戶權(quán)限的控制
      2025-02-02
    • SpringBoot項目@Async方法問題解決方案

      SpringBoot項目@Async方法問題解決方案

      這篇文章主要介紹了SpringBoot項目@Async方法問題解決方案,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
      2020-04-04
    • java程序設(shè)計語言的優(yōu)勢及特點

      java程序設(shè)計語言的優(yōu)勢及特點

      在本篇文章里小編給大家分享的是一篇關(guān)于java程序設(shè)計語言的優(yōu)勢及特點的內(nèi)容,需要的朋友們可以學(xué)習(xí)參考下。
      2020-02-02
    • Java List 使用舉例(從入門到精通)

      Java List 使用舉例(從入門到精通)

      本文系統(tǒng)講解Java List,涵蓋基礎(chǔ)概念、核心特性、常用實現(xiàn)(如ArrayList、LinkedList)及性能對比,介紹創(chuàng)建、操作、遍歷方法,結(jié)合實戰(zhàn)案例,提供選擇策略和優(yōu)化技巧,幫助高效使用List,感興趣的朋友跟隨小編一起看看吧
      2025-08-08

    最新評論

    全椒县| 灌南县| 武陟县| 东光县| 襄汾县| 许昌县| 东丽区| 青神县| 溧水县| 江达县| 航空| 卢湾区| 蒙山县| 集安市| 无锡市| 巴南区| 高清| 邯郸市| 信宜市| 高密市| 临沂市| 福州市| 南部县| 井研县| 潮安县| 天峻县| 克什克腾旗| 三门峡市| 凉山| 兴安盟| 辽宁省| 庆城县| 海林市| 孟连| 肃南| 应用必备| 鄂托克旗| 布拖县| 太和县| 班戈县| 石城县|