欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

如何使用Spring boot的@Transactional進(jìn)行事務(wù)管理

 更新時(shí)間:2025年02月11日 15:25:52   作者:TracyCoder123  
這篇文章介紹了SpringBoot中使用@Transactional注解進(jìn)行聲明式事務(wù)管理的詳細(xì)信息,包括基本用法、核心配置參數(shù)、關(guān)鍵注意事項(xiàng)、調(diào)試技巧、最佳實(shí)踐以及完整示例,感興趣的朋友一起看看吧

在 Spring Boot 中,@Transactional 是用于聲明式事務(wù)管理的關(guān)鍵注解。它基于 Spring 的 AOP(面向切面編程)實(shí)現(xiàn),可以簡(jiǎn)化數(shù)據(jù)庫(kù)事務(wù)的管理。

一、前置條件

  • 依賴(lài)引入:確保項(xiàng)目中包含 spring-boot-starter-data-jpaspring-boot-starter-jdbc
  • 啟用事務(wù)管理:Spring Boot 默認(rèn)自動(dòng)配置事務(wù)管理器(如 DataSourceTransactionManager),無(wú)需手動(dòng)啟用。

二、基本用法

1. 在方法上添加注解

@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;
    @Transactional
    public void createUser(User user) {
        userRepository.save(user);
        // 其他數(shù)據(jù)庫(kù)操作
    }
}

2. 在類(lèi)上添加注解

@Service
@Transactional
public class UserService {
    // 類(lèi)中所有 public 方法都會(huì)應(yīng)用事務(wù)
}

三、核心配置參數(shù)

1. 傳播行為(Propagation)

控制事務(wù)的邊界,默認(rèn)為 Propagation.REQUIRED。

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateUser(User user) {
    // 始終開(kāi)啟新事務(wù)
}

常見(jiàn)選項(xiàng):

  • REQUIRED(默認(rèn)):如果當(dāng)前存在事務(wù),則加入;否則新建
  • REQUIRES_NEW:始終新建事務(wù),掛起當(dāng)前事務(wù)(如有)
  • SUPPORTS:如果當(dāng)前存在事務(wù),則加入;否則非事務(wù)運(yùn)行
  • NOT_SUPPORTED:非事務(wù)運(yùn)行,掛起當(dāng)前事務(wù)(如有)
  • MANDATORY:必須在事務(wù)中調(diào)用,否則拋出異常
  • NEVER:必須在非事務(wù)中調(diào)用,否則拋出異常

2. 隔離級(jí)別(Isolation)

控制事務(wù)的隔離性,默認(rèn)為 Isolation.DEFAULT(使用數(shù)據(jù)庫(kù)默認(rèn))。

@Transactional(isolation = Isolation.SERIALIZABLE)
public void sensitiveOperation() {
    // 最高隔離級(jí)別
}

3. 超時(shí)時(shí)間(Timeout)

事務(wù)超時(shí)時(shí)間(秒),默認(rèn)-1(使用數(shù)據(jù)庫(kù)默認(rèn))。

@Transactional(timeout = 30)
public void longRunningProcess() {
    // 超過(guò)30秒將回滾
}

4. 只讀模式(readOnly)

優(yōu)化只讀操作,默認(rèn)為 false

@Transactional(readOnly = true)
public List<User> findAllUsers() {
    return userRepository.findAll();
}

5. 回滾規(guī)則(rollbackFor/noRollbackFor)

指定觸發(fā)回滾的異常類(lèi)型:

@Transactional(rollbackFor = CustomException.class)
public void process() throws CustomException {
    // 拋出 CustomException 時(shí)回滾
}

四、關(guān)鍵注意事項(xiàng)

1. 方法可見(jiàn)性

必須為 public:由于 Spring AOP 的實(shí)現(xiàn)機(jī)制,非 public 方法上的 @Transactional 無(wú)效

2. 自調(diào)用問(wèn)題

同類(lèi)中的方法互相調(diào)用時(shí),事務(wù)不會(huì)生效(繞過(guò)代理對(duì)象)

// 錯(cuò)誤示例
public void methodA() {
    methodB(); // 事務(wù)不生效
}
@Transactional
public void methodB() { ... }

3. 異常處理

  • 默認(rèn)回滾條件:拋出 RuntimeException 或 Error
  • 檢查型異常(Checked Exception)默認(rèn)不會(huì)觸發(fā)回滾
// 處理檢查型異常
@Transactional(rollbackFor = IOException.class)
public void fileOperation() throws IOException {
    // ...
}

4. 多數(shù)據(jù)源事務(wù)

需配置多個(gè)事務(wù)管理器,并通過(guò) @Transactional(value = "specificTransactionManager") 指定

五、調(diào)試技巧

啟用調(diào)試日志:

logging.level.org.springframework.transaction.interceptor=TRACE
logging.level.org.springframework.jdbc.datasource.DataSourceTransactionManager=DEBUG

檢查代理對(duì)象:

System.out.println(userService.getClass().getName());
// 輸出應(yīng)為代理類(lèi):com.sun.proxy.$ProxyXX 或 ...$$EnhancerBySpringCGLIB$$...

六、最佳實(shí)踐

  • 服務(wù)層使用:在 Service 層而非 Controller 層使用事務(wù)
  • 保持短事務(wù):避免在事務(wù)中包含遠(yuǎn)程調(diào)用、文件IO等耗時(shí)操作
  • 精確回滾規(guī)則:明確指定 rollbackFor 而非依賴(lài)默認(rèn)行為
  • 結(jié)合 JPA 使用
@Transactional
public void updateUserEmail(Long userId, String email) {
    User user = userRepository.findById(userId).orElseThrow();
    user.setEmail(email); // 自動(dòng)臟檢查,事務(wù)提交時(shí)更新
}

七、完整示例

@Service
public class OrderService {
    @Autowired
    private OrderRepository orderRepository;
    @Autowired
    private InventoryService inventoryService;
    @Transactional(
        propagation = Propagation.REQUIRED,
        isolation = Isolation.READ_COMMITTED,
        timeout = 30,
        rollbackFor = {InsufficientStockException.class, PaymentFailedException.class}
    )
    public void placeOrder(Order order) {
        inventoryService.reduceStock(order.getItems()); // 可能拋出 InsufficientStockException
        orderRepository.save(order);
        processPayment(order); // 可能拋出 PaymentFailedException
    }
    private void processPayment(Order order) {
        // 支付邏輯
    }
}

八、適用于關(guān)系型數(shù)據(jù)庫(kù)

@Transactional 的使用與數(shù)據(jù)庫(kù)層有直接關(guān)系,但它的事務(wù)管理機(jī)制是基于數(shù)據(jù)庫(kù)事務(wù)的。如果 Service 層方法使用了 Elasticsearch 客戶(hù)端讀寫(xiě) Elasticsearch,那么 @Transactional 的行為會(huì)受到影響。

1.@Transactional 的適用范圍

  • @Transactional 是 Spring 提供的事務(wù)管理機(jī)制,主要用于管理數(shù)據(jù)庫(kù)事務(wù)。
  • 它依賴(lài)于底層的事務(wù)管理器(如 DataSourceTransactionManager),而這些事務(wù)管理器通常是與關(guān)系型數(shù)據(jù)庫(kù)(如 MySQL、PostgreSQL)交互的。

數(shù)據(jù)庫(kù)事務(wù)@Transactional 可以確保數(shù)據(jù)庫(kù)操作的原子性、一致性、隔離性和持久性(ACID)。非數(shù)據(jù)庫(kù)操作:對(duì)于非數(shù)據(jù)庫(kù)操作(如 Elasticsearch、Redis、文件系統(tǒng)等),@Transactional 無(wú)法直接管理其事務(wù)。

2.Elasticsearch 與 @Transactional 的關(guān)系

Elasticsearch 是一個(gè)分布式搜索引擎,它本身不支持傳統(tǒng)意義上的事務(wù)(ACID)。因此,@Transactional 對(duì) Elasticsearch 的操作沒(méi)有直接的事務(wù)管理能力。

(1)場(chǎng)景分析

假設(shè)我們的 Service 方法同時(shí)操作了數(shù)據(jù)庫(kù)和 Elasticsearch:

@Service
public class UserService {
    @Autowired
    private UserRepository userRepository; // 數(shù)據(jù)庫(kù)操作
    @Autowired
    private ElasticsearchClient elasticsearchClient; // Elasticsearch 操作
    @Transactional
    public void createUser(User user) {
        // 操作數(shù)據(jù)庫(kù)
        userRepository.save(user);
        // 操作 Elasticsearch
        IndexRequest request = new IndexRequest("users")
            .id(user.getId().toString())
            .source("name", user.getName(), "email", user.getEmail());
        elasticsearchClient.index(request, RequestOptions.DEFAULT);
    }
}

(2)可能出現(xiàn)的問(wèn)題

  • 數(shù)據(jù)庫(kù)事務(wù)回滾,Elasticsearch 操作不回滾:
  • 如果 userRepository.save(user) 成功,但后續(xù) Elasticsearch 操作失敗,數(shù)據(jù)庫(kù)事務(wù)會(huì)回滾(因?yàn)?@Transactional 生效),但 Elasticsearch 的數(shù)據(jù)已經(jīng)寫(xiě)入,無(wú)法回滾。
  • 數(shù)據(jù)庫(kù)事務(wù)提交,Elasticsearch 操作失敗:
  • 如果數(shù)據(jù)庫(kù)操作成功,但 Elasticsearch 操作失敗,數(shù)據(jù)庫(kù)事務(wù)已經(jīng)提交,而 Elasticsearch 數(shù)據(jù)未更新,導(dǎo)致數(shù)據(jù)不一致。

3.如何解決 Elasticsearch 與數(shù)據(jù)庫(kù)的事務(wù)一致性問(wèn)題

由于 Elasticsearch 不支持事務(wù),因此需要采用其他機(jī)制來(lái)保證數(shù)據(jù)一致性。

(1)手動(dòng)補(bǔ)償機(jī)制 在 Elasticsearch 操作失敗時(shí),手動(dòng)回滾數(shù)據(jù)庫(kù)操作。

示例:

@Transactional
public void createUser(User user) {
    try {
        userRepository.save(user); // 數(shù)據(jù)庫(kù)操作
        IndexRequest request = new IndexRequest("users")
            .id(user.getId().toString())
            .source("name", user.getName(), "email", user.getEmail());
        elasticsearchClient.index(request, RequestOptions.DEFAULT); // Elasticsearch 操作
    } catch (Exception e) {
        // Elasticsearch 操作失敗,手動(dòng)回滾數(shù)據(jù)庫(kù)
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        throw e;
    }
}

(2)消息隊(duì)列(最終一致性)

  • 將 Elasticsearch 操作異步化,通過(guò)消息隊(duì)列(如 Kafka、RabbitMQ)實(shí)現(xiàn)最終一致性。
  • 示例:

    數(shù)據(jù)庫(kù)操作完成后,發(fā)送消息到隊(duì)列。

    消費(fèi)者從隊(duì)列中讀取消息并更新 Elasticsearch。

(3)兩階段提交(2PC)

  • 使用分布式事務(wù)管理器(如 Seata)實(shí)現(xiàn)數(shù)據(jù)庫(kù)和 Elasticsearch 的分布式事務(wù)。
  • 這種方法復(fù)雜度較高,通常不推薦用于 Elasticsearch。

(4)本地消息表

  • 在數(shù)據(jù)庫(kù)中創(chuàng)建一張消息表,記錄需要同步到 Elasticsearch 的數(shù)據(jù)。
  • 通過(guò)定時(shí)任務(wù)或事件監(jiān)聽(tīng)器將數(shù)據(jù)同步到 Elasticsearch。

總結(jié)

  • @Transactional 只對(duì)數(shù)據(jù)庫(kù)事務(wù)有效:它無(wú)法管理 Elasticsearch 等非關(guān)系型數(shù)據(jù)存儲(chǔ)的事務(wù)。
  • Elasticsearch 操作與數(shù)據(jù)庫(kù)事務(wù)的一致性:需要通過(guò)補(bǔ)償機(jī)制、消息隊(duì)列等方式實(shí)現(xiàn)。
    • 設(shè)計(jì)建議: 盡量避免在同一個(gè)事務(wù)中混合數(shù)據(jù)庫(kù)和 Elasticsearch 操作。
    • 采用異步化或最終一致性方案來(lái)保證數(shù)據(jù)一致性。

如果你有更多具體的業(yè)務(wù)場(chǎng)景,可以進(jìn)一步討論如何設(shè)計(jì)解決方案!

到此這篇關(guān)于使用Spring boot的@Transactional進(jìn)行事務(wù)管理的文章就介紹到這了,更多相關(guān)Spring boot @Transactional事務(wù)管理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • spring解決循環(huán)依賴(lài)的方案示例

    spring解決循環(huán)依賴(lài)的方案示例

    這篇文章主要介紹spring如何解決循環(huán)依賴(lài),文中有相關(guān)的代碼示例給大家參考,對(duì)我們的學(xué)習(xí)或工作有一定的幫助,感興趣的同學(xué)可以借鑒閱讀
    2023-05-05
  • JAVA面向?qū)ο?封裝原理及實(shí)例解析

    JAVA面向?qū)ο?封裝原理及實(shí)例解析

    這篇文章主要介紹了JAVA面向?qū)ο?封裝原理及實(shí)例解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • java判斷今天,昨天,前天,不能用秒間隔的簡(jiǎn)單實(shí)例

    java判斷今天,昨天,前天,不能用秒間隔的簡(jiǎn)單實(shí)例

    下面小編就為大家?guī)?lái)一篇java判斷今天,昨天,前天,不能用秒間隔的簡(jiǎn)單實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-03-03
  • Spring Boot如何使用AOP實(shí)例解析

    Spring Boot如何使用AOP實(shí)例解析

    這篇文章主要介紹了Spring Boot如何使用AOP實(shí)例解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-04-04
  • 一文帶你搞懂Spring響應(yīng)式編程

    一文帶你搞懂Spring響應(yīng)式編程

    相信響應(yīng)式編程經(jīng)常會(huì)在各種地方被提到。本篇就為大家從函數(shù)式編程一直到Spring?WeFlux做一次簡(jiǎn)單的講解,并給出一些示例,希望大家可以更好的理解響應(yīng)式編程
    2022-07-07
  • Java如何利用遞歸計(jì)算出階乘

    Java如何利用遞歸計(jì)算出階乘

    這篇文章主要介紹了Java如何通過(guò)遞歸計(jì)算出階乘,文中介紹了遞歸的使用方法和基本特點(diǎn),以及相關(guān)示例代碼,對(duì)大家的學(xué)習(xí)有一定的幫助,需要的朋友可以參考下
    2023-05-05
  • java迭代器中刪除元素的實(shí)例操作詳解

    java迭代器中刪除元素的實(shí)例操作詳解

    在本篇內(nèi)容里小編給各位分享了一篇關(guān)于java迭代器中刪除元素的實(shí)例操作詳解內(nèi)容,有興趣的朋友們可以學(xué)習(xí)下。
    2021-01-01
  • MyBatis使用注解開(kāi)發(fā)實(shí)現(xiàn)步驟解析

    MyBatis使用注解開(kāi)發(fā)實(shí)現(xiàn)步驟解析

    這篇文章主要介紹了MyBatis使用注解開(kāi)發(fā)實(shí)現(xiàn)步驟解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-08-08
  • java讀寫(xiě)oracle的blob字段示例

    java讀寫(xiě)oracle的blob字段示例

    這篇文章主要介紹了java讀寫(xiě)oracle的blob字段示例,需要的朋友可以參考下
    2014-02-02
  • java JSON解析庫(kù)Alibaba Fastjson用法詳解

    java JSON解析庫(kù)Alibaba Fastjson用法詳解

    這篇文章主要介紹了java JSON解析庫(kù)Alibaba Fastjson用法,結(jié)合實(shí)例形式詳細(xì)分析了java JSON解析庫(kù)Alibaba Fastjson的基本功能、原理、用法及操作注意事項(xiàng),需要的朋友可以參考下
    2020-04-04

最新評(píng)論