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

別踩坑!Spring Boot 多線程事務(wù)處理最佳實(shí)踐全解析

開發(fā) 前端
在 Spring Boot 中處理多線程事務(wù),看似簡單,實(shí)則充滿陷阱。核心挑戰(zhàn)在于:線程與事務(wù)上下文的綁定機(jī)制。

在構(gòu)建企業(yè)級系統(tǒng)時(shí),事務(wù)管理 是數(shù)據(jù)一致性與系統(tǒng)穩(wěn)定性的基石。然而,一旦引入 多線程,Spring Boot 的事務(wù)就會(huì)變得棘手:父線程開啟的事務(wù)默認(rèn)無法傳遞到子線程,導(dǎo)致連接異常、數(shù)據(jù)不一致,甚至死鎖等問題。

本文將帶你從原理出發(fā),逐步剖析 Spring Boot 中 多線程事務(wù)的潛在陷阱,并給出 三種可靠的解決方案,最后總結(jié)一些在實(shí)戰(zhàn)中必須遵循的 最佳實(shí)踐。

為什么多線程事務(wù)這么麻煩? 

在 Spring Boot 中,事務(wù)通常通過 @Transactional 管理,底層依賴 PlatformTransactionManager 來維護(hù) 線程綁定的事務(wù)上下文。

問題是:事務(wù)上下文是 ThreadLocal 級別的,也就是說,父線程開啟的事務(wù)無法自動(dòng)被子線程感知。這會(huì)導(dǎo)致:

  • 事務(wù)傳播問題:子線程不繼承父線程事務(wù),邏輯混亂;
  • 數(shù)據(jù)一致性風(fēng)險(xiǎn):多個(gè)線程并發(fā)寫操作容易引發(fā)臟數(shù)據(jù)或丟失更新;
  • 連接管理異常:數(shù)據(jù)庫連接與事務(wù)綁定,不正確的線程共享可能報(bào)錯(cuò);
  • 性能隱患:如果沒設(shè)計(jì)好,線程池 + 事務(wù)很容易拖垮數(shù)據(jù)庫。

多線程場景下事務(wù)的默認(rèn)行為 

在默認(rèn)情況下,Spring 的事務(wù)只在 當(dāng)前線程 有效。

比如下面的例子:

package com.icoderoad.demo.service;


import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


@Service
public class TransactionService {
    @Transactional
    public void processWithThreads() {
        // 父線程中保存數(shù)據(jù)
        saveData("Parent Data");


        // 開啟新線程
        ExecutorService executor = Executors.newFixedThreadPool(1);
        executor.submit(() -> {
            // 子線程執(zhí)行,無法加入父線程事務(wù)
            saveData("Child Data"); // 可能報(bào)錯(cuò)或開新連接
        });
        executor.shutdown();
    }


    private void saveData(String data) {
        System.out.println("Saving: " + data);
    }
}

此時(shí)問題包括:

  • 子線程的數(shù)據(jù)保存不在父事務(wù)中;
  • 父事務(wù)回滾不會(huì)影響子線程;
  • 部分?jǐn)?shù)據(jù)可能已落庫,出現(xiàn)不一致。

三種可行的解決方案 

使用 TransactionTemplate 傳遞事務(wù)上下文 

Spring 提供了 TransactionTemplate,它支持 編程式事務(wù)控制,可以在子線程中執(zhí)行父事務(wù)的邏輯。

package com.icoderoad.demo.service;


import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;


import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


@Service
public class TransactionService {
    private final TransactionTemplate transactionTemplate;


    public TransactionService(TransactionTemplate transactionTemplate) {
        this.transactionTemplate = transactionTemplate;
    }


    @Transactional
    public void processWithThreads() {
        saveData("Parent Data");


        ExecutorService executor = Executors.newFixedThreadPool(1);
        executor.submit(() -> {
            transactionTemplate.execute(status -> {
                saveData("Child Data"); // 在同一事務(wù)中運(yùn)行
                return null;
            });
        });
        executor.shutdown();
    }


    private void saveData(String data) {
        System.out.println("Saving: " + data);
    }
}

優(yōu)點(diǎn):事務(wù)可控,父子線程共享事務(wù),回滾一致。

缺點(diǎn):需要手動(dòng)編寫事務(wù)邏輯,連接池必須支持線程安全。

 使用事務(wù)感知的異步執(zhí)行器 ??

Spring 提供了 異步任務(wù)執(zhí)行器,可通過 任務(wù)裝飾器 將事務(wù)上下文傳遞到子線程。

配置示例:

package com.icoderoad.demo.config;


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.interceptor.TransactionInterceptor;


@Configuration
@EnableAsync
@EnableTransactionManagement
public class AsyncConfig {
    @Bean
    public SimpleAsyncTaskExecutor taskExecutor(TransactionInterceptor interceptor) {
        SimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor();
        executor.setTaskDecorator(runnable -> interceptor.invoke(null, runnable));
        return executor;
    }
}

在 Service 中使用:

package com.icoderoad.demo.service;


import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;


@Service
public class TransactionService {


    @Transactional
    public void processWithThreads() {
        saveData("Parent Data");
        processAsync(); // 異步調(diào)用
    }


    @Async
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void processAsync() {
        saveData("Child Data"); // 新線程執(zhí)行
    }


    private void saveData(String data) {
        System.out.println("Saving: " + data);
    }
}

優(yōu)點(diǎn):通過 Spring 機(jī)制自動(dòng)處理事務(wù)邊界,線程安全。

缺點(diǎn):配置復(fù)雜,不適合極大規(guī)模的異步調(diào)用。

子線程獨(dú)立開啟新事務(wù) 

如果子線程的邏輯和父線程相對獨(dú)立,可以為它們單獨(dú)開事務(wù)。

package com.icoderoad.demo.service;


import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;


import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


@Service
public class TransactionService {
    @Transactional
    public void processWithThreads() {
        saveData("Parent Data");


        ExecutorService executor = Executors.newFixedThreadPool(1);
        executor.submit(this::processInNewTransaction);
        executor.shutdown();
    }


    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void processInNewTransaction() {
        saveData("Child Data"); // 獨(dú)立事務(wù)
    }


    private void saveData(String data) {
        System.out.println("Saving: " + data);
    }
}

優(yōu)點(diǎn):事務(wù)隔離,子線程不依賴父事務(wù)。

缺點(diǎn):更多的數(shù)據(jù)庫連接開銷,需注意一致性控制。

常見陷阱與規(guī)避方法 

  • NoTransactionException:子線程無事務(wù)上下文時(shí)會(huì)報(bào)錯(cuò) → 使用 TransactionTemplate 或事務(wù)感知執(zhí)行器。
  • 連接池不足:多線程事務(wù)可能消耗額外連接 → 調(diào)整 HikariCP 配置并監(jiān)控連接數(shù)。
  • 競爭條件:多個(gè)線程并發(fā)修改數(shù)據(jù) → 使用樂觀鎖(@Version)或悲觀鎖。
  • 死鎖風(fēng)險(xiǎn):避免長事務(wù)和嵌套事務(wù),測試高并發(fā)下的鎖沖突。
  • 性能瓶頸:事務(wù)越長越耗資源 → 使用批處理和短事務(wù)。

最佳實(shí)踐總結(jié) 

  • 事務(wù)盡量短,減少鎖持有時(shí)間;
  • 合理選擇傳播機(jī)制:共享事務(wù)用 REQUIRED,獨(dú)立事務(wù)用 REQUIRES_NEW;
  • 使用線程安全的數(shù)據(jù)源(如 HikariCP);
  • 并發(fā)壓測:通過 JMeter 等工具提前發(fā)現(xiàn)問題;
  • 監(jiān)控事務(wù):使用 Spring Boot Actuator 或數(shù)據(jù)庫日志追蹤事務(wù)情況;
  • 避免共享可變狀態(tài),盡量使用不可變對象。

 結(jié)論 

在 Spring Boot 中處理多線程事務(wù),看似簡單,實(shí)則充滿陷阱。核心挑戰(zhàn)在于:線程與事務(wù)上下文的綁定機(jī)制。

本文介紹的三種方案:

  1. TransactionTemplate(顯式傳遞事務(wù))
  2. 事務(wù)感知執(zhí)行器(異步任務(wù)自動(dòng)傳播)
  3. 獨(dú)立事務(wù)(子線程新開事務(wù))

各有優(yōu)缺點(diǎn),需要結(jié)合業(yè)務(wù)特點(diǎn)進(jìn)行選擇。

只要遵循本文的 最佳實(shí)踐(短事務(wù)、合理傳播、線程安全的數(shù)據(jù)源、充分壓測),就能在復(fù)雜并發(fā)環(huán)境下依舊保證 數(shù)據(jù)一致性 和 系統(tǒng)穩(wěn)定性

責(zé)任編輯:武曉燕 來源: 路條編程
相關(guān)推薦

2009-07-15 17:41:55

iBATIS事務(wù)處理

2011-04-27 15:55:16

2009-09-14 19:55:03

LINQ事務(wù)處理

2009-07-09 18:15:42

JDBC事務(wù)處理

2009-11-13 17:01:07

ADO.NET事務(wù)處理

2014-01-22 13:37:53

2010-04-13 15:44:00

Oracle與SqlS

2010-01-04 13:06:50

ADO.NET事務(wù)

2022-06-22 05:42:32

數(shù)據(jù)庫事務(wù)處理分析查詢

2010-05-17 14:59:05

MySQL事務(wù)處理

2022-06-13 10:42:21

分布式事務(wù)數(shù)據(jù)庫

2009-04-15 17:03:15

OracleSQL Server事務(wù)處理

2009-11-04 15:05:45

ADO.NET事務(wù)

2017-04-10 13:30:47

Redis數(shù)據(jù)庫命令

2011-04-27 16:09:48

SQL ServerSSIS

2014-02-11 09:07:31

2010-01-13 14:13:24

VB.NET事務(wù)處理

2011-05-18 08:34:45

javaJDBC

2009-06-16 11:42:00

JDBC事務(wù)處理JavaBean

2011-03-15 10:22:42

SQL Server 聯(lián)機(jī)事務(wù)處理
點(diǎn)贊
收藏

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