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

@Transactional用法詳解與事務(wù)避坑指南

 更新時間:2025年10月23日 10:49:56   作者:-朽木  
這篇文章主要介紹了@Transactional用法與事務(wù)避坑指南,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
  • 需求:業(yè)務(wù)單位需要觀測訂單動態(tài),所以要在訂單的各個狀態(tài)節(jié)點上傳狀態(tài)至狀態(tài)池系統(tǒng)
  • 方案:又是Easy的需求,不就是在每個訂單狀態(tài)改變時觸發(fā)上傳狀態(tài),為了不影響訂單正常流轉(zhuǎn),增加一個消息中間件MQ

前言

在Java中,@Transactional是一個非常重要的注解,用于聲明事務(wù)管理的行為。

它可以被應(yīng)用在類級別或方法級別上,并且提供了多種選項來控制事務(wù)的傳播行為、隔離級別、超時設(shè)置和回滾條件等。

一、Java的@Transactional解釋

@Transactional 注解在 Java 中用于聲明式事務(wù)管理,它可以應(yīng)用于接口、接口方法、類以及類的方法上。在默認配置下,Spring 中的 @Transactional 注解會使得方法在事務(wù)的上下文中執(zhí)行,其事務(wù)邊界默認為方法開始執(zhí)行時開始,方法正常結(jié)束時提交事務(wù),方法執(zhí)行過程中拋出異常時回滾事務(wù)。

但是,你可以通過在 @Transactional 注解中設(shè)置 propagation 屬性來改變事務(wù)的傳播行為,例如可以設(shè)置為Propagation.MANDATORY,這意味著該方法必須在一個已經(jīng)存在的事務(wù)中執(zhí)行,否則就會拋出異常。

另外,你可以通過設(shè)置 phase 屬性來改變事務(wù)的提交時機,例如可以設(shè)置為Phase.AFTER_COMPLETION,這樣事務(wù)就會在整個事務(wù)完成后提交,不論事務(wù)是正常結(jié)束還是異常結(jié)束。

以下是一個使用 @Transactional 注解的示例,其中 propagation 設(shè)置為Propagation.REQUIRED(默認值),表示如果當(dāng)前存在事務(wù),則加入該事務(wù);如果不存在,則創(chuàng)建一個新的事務(wù)。

import org.springframework.transaction.annotation.Transactional;
import org.springframework.stereotype.Service;
 
@Service
public class MyService {
 
    @Transactional
    public void someTransactionalMethod() {
        // 方法執(zhí)行的代碼
    }
}

二、踩坑

接到的需求中:每個訂單狀態(tài)改變時觸發(fā)上傳狀態(tài),為了不影響訂單正常流轉(zhuǎn),增加一個消息中間件MQ

流程圖如下:

二、狀態(tài)統(tǒng)一入口:推送

    private SendResult sendStatusToMq(SendStatusPoolMsgVo sendStatusPoolMsgVo) {
        String msg = JSON.toJSONString(sendStatusPoolMsgVo, SerializerFeature.PrettyFormat,
                SerializerFeature.WriteMapNullValue);
        LOGGER.info("sendStatusPoolMsgToMq,發(fā)送的消息{}", msg);
        Message<String> message = MessageBuilder.withPayload(msg).build();
        SendResult sendResult = new SendResult();
        try {
            sendResult = rocketMQTemplate.syncSend(statusPoolTopic, message, 3000, 2);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("sendStatusToMq err", e);
            TaskMqModel taskMqModel = new TaskMqModel();
            taskMqModel.setTopic(statusPoolTopic);
            taskMqModel.setMessageType(MessageTypeConstant.MQ_SUPPLE_STATUSPOOL);
            taskMqModel.setDisposeFlag(RequestConstant.REQUEST_ORIGINAL);
            taskMqModel.setRawMessage(msg);
            taskMqModel.setCreateTime(new Date());
            taskMqService.save(taskMqModel);
        }
        return sendResult;
    }

我這里做了個狀態(tài)統(tǒng)一入口,同時為了避免推送MQ服務(wù)失敗,做了個異常捕獲保存推送消息,方便重推。

三、MQ消費

// ... 其他業(yè)務(wù)邏輯 ...
        // 獲取訂單信息
        String orderNo = msgVo.getOrderNo();
        orderModel orderModel = orderService.getOrderByOrderNo(orderNo);
        //如果是客戶下單再去待處理訂單查詢
        if (Objects.isNull(fmOrderModel)) {
            LOGGER.err("未查到信息,初始化失敗!");
            return;
        }
//

然后我的日志全是:

[2024-08-8 08:36:50.161][ERROR][ConsumeMessageThread_2] 未查到信息,初始化失敗!
[2024-08-8 08:37:57.015][ERROR][ConsumeMessageThread_2] 未查到信息,初始化失??!
[2024-08-8 08:42:45.536][ERROR][ConsumeMessageThread_2] 未查到信息,初始化失?。?

我查看數(shù)據(jù)庫是完全能查到的,有點奇怪????????

四、問題與解決

在Java中,@Transactional 注解通常用于聲明方法執(zhí)行的事務(wù)邊界,確保方法內(nèi)的一系列操作要么全部成功,要么全部失敗。它通常與Spring框架的事務(wù)管理器一起使用,以提供聲明式的事務(wù)管理。

如果你的訂單數(shù)據(jù)保存操作使用了 @Transactional,并且在保存數(shù)據(jù)之后立即推送消息到消息隊列(MQ),那么消費者可能查不到數(shù)據(jù)的原因可能與事務(wù)的隔離級別有關(guān)。

下面是我搜到的一些可能導(dǎo)致該問題的原因:

  1. 事務(wù)隔離級別:如果你的數(shù)據(jù)庫事務(wù)使用了較高的隔離級別(如可重復(fù)讀或串行化),那么在事務(wù)提交之前,其他事務(wù)(包括MQ消費者)可能看不到該事務(wù)所做的更改。
  2. 事務(wù)傳播行為:如果MQ消費者也運行在Spring管理的事務(wù)中,并且事務(wù)的傳播行為設(shè)置為不支持當(dāng)前事務(wù)(例如,Propagation.NOT_SUPPORTED),那么消費者可能會在不同的事務(wù)上下文中運行,從而看不到未提交的更改。
  3. 延遲提交:如果事務(wù)在消息發(fā)送之后才提交,MQ消費者可能會在事務(wù)提交之前讀取數(shù)據(jù)庫,因此看不到新數(shù)據(jù)。
  4. MQ消息延遲:如果消息隊列本身存在延遲,消費者可能會在數(shù)據(jù)還未寫入數(shù)據(jù)庫時就接收到消息。
  5. 數(shù)據(jù)庫緩存:某些數(shù)據(jù)庫實現(xiàn)可能會緩存數(shù)據(jù),這可能導(dǎo)致即使數(shù)據(jù)已經(jīng)寫入,消費者也無法立即看到更新。
  6. MQ消費者處理邏輯:如果MQ消費者在處理消息時沒有正確地處理事務(wù)或數(shù)據(jù)庫查詢,也可能導(dǎo)致查不到數(shù)據(jù)。

解決方式

在Spring框架中,我通過實現(xiàn)TransactionSynchronization接口來在事務(wù)提交后執(zhí)行回調(diào)操作。

以下是實現(xiàn)事務(wù)提交回調(diào)發(fā)送消息的方法:

@Component
public class TransactionalMessageSender implements TransactionSynchronization {

    @Autowired
    private SomeMessageService messageService; // 消息發(fā)送服務(wù)

    @Override
    public void beforeCommit(boolean readOnly) {
        // 這里可以執(zhí)行一些操作,但事務(wù)還未提交
    }

    @Override
    public void beforeCompletion() {
        // 事務(wù)即將提交,可以在這里準備發(fā)送消息
    }

    @Override
    public void afterCommit() {
        // 事務(wù)已經(jīng)提交,可以在這里發(fā)送消息
        sendResult = rocketMQTemplate.syncSend(statusPoolTopic, message, 3000, 2);
    }

    @Override
    public void afterCompletion(TransactionStatus status) {
        // 事務(wù)已經(jīng)完成,無論是提交還是回滾
        if (status == TransactionStatus.COMMITTED) {
            // 這里可以執(zhí)行一些事務(wù)提交后的清理工作
        }
    }
}

五、總結(jié)

在 Spring 框架中使用 @Transactional 注解時,事務(wù)管理器會在事務(wù)邊界內(nèi)管理數(shù)據(jù)庫操作。

當(dāng)你在一個事務(wù)中執(zhí)行數(shù)據(jù)庫操作后立即發(fā)送消息到消息隊列(MQ),可能會遇到一個問題:MQ 消費者在接收到消息并嘗試查詢數(shù)據(jù)庫時,發(fā)現(xiàn)數(shù)據(jù)庫中并沒有預(yù)期的數(shù)據(jù)。

這個問題的根本原因在于事務(wù)的隔離級別和事務(wù)提交的時間點。

當(dāng)事務(wù)尚未提交時,其他事務(wù)(包括 MQ 消費者的查詢操作)是無法看到該事務(wù)內(nèi)的修改的。

即使你在事務(wù)中已經(jīng)執(zhí)行了數(shù)據(jù)庫操作(如插入或更新),這些修改對其他事務(wù)來說仍然是不可見的,直到當(dāng)前事務(wù)提交。

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

相關(guān)文章

  • Java matches類,Pattern類及matcher類用法示例

    Java matches類,Pattern類及matcher類用法示例

    這篇文章主要介紹了Java matches類,Pattern類及matcher類用法,結(jié)合實例形式分析了java matches類,Pattern類及matcher類針對字符串常見操作技巧與相關(guān)注意事項,需要的朋友可以參考下
    2019-03-03
  • SpringBoot中緩存@Cacheable出錯的問題解決

    SpringBoot中緩存@Cacheable出錯的問題解決

    本文主要介紹了SpringBoot中緩存@Cacheable出錯的問題解決,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-10-10
  • mybatisPlus批量插入優(yōu)化加快性能

    mybatisPlus批量插入優(yōu)化加快性能

    這篇文章主要介紹了mybatisPlus批量插入優(yōu)化加快性能,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-12-12
  • 利用Jackson解決Json序列化和反序列化問題

    利用Jackson解決Json序列化和反序列化問題

    Jackson是一個用于處理Json數(shù)據(jù)的Java庫,它提供了一系列功能,包括Json序列化和反序列化,所以本文就來講講如何利用利用Jackson解決Json序列化和反序列化的問題吧
    2023-05-05
  • Java程序?qū)崿F(xiàn)導(dǎo)出Excel的方法(支持IE低版本)

    Java程序?qū)崿F(xiàn)導(dǎo)出Excel的方法(支持IE低版本)

    下面小編就為大家?guī)硪黄狫ava程序?qū)崿F(xiàn)導(dǎo)出Excel的方法(支持IE低版本)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-07-07
  • 深入理解jvm啟動參數(shù)

    深入理解jvm啟動參數(shù)

    JVM的啟動參數(shù)是在啟動JVM時可以設(shè)置的一些命令行參數(shù),本文詳細的介紹了深入理解jvm啟動參數(shù),具有一定的參考價值,感興趣的可以了解一下
    2023-08-08
  • java讀取resource目錄下文件的方法示例

    java讀取resource目錄下文件的方法示例

    這篇文章主要介紹了利用java讀取resource目錄下文件的方法,文中給出了詳細的示例代碼,相信對大家具有一定的參考借鑒,需要的朋友們下面來一起看看吧。
    2017-02-02
  • Java中斷線程的方法

    Java中斷線程的方法

    這篇文章主要介紹了Java中斷線程的方法,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2017-05-05
  • Java屬性嵌套獲取值的實現(xiàn)方式

    Java屬性嵌套獲取值的實現(xiàn)方式

    本文介紹了如何使用MybatisMetaObject類和FieldUtil工具類來簡化Java類嵌套獲取屬性值的過程,通過這種方式,可以避免逐層檢查和判空操作,直接從實例對象中獲取深層嵌套的屬性值,并且在任意一層為空時自動返回null,不會報錯
    2025-11-11
  • java判斷兩個時間是不是同一天的方法

    java判斷兩個時間是不是同一天的方法

    這篇文章主要介紹了java判斷兩個時間是不是同一天的方法,需要的朋友可以參考下
    2014-02-02

最新評論

锡林浩特市| 图木舒克市| 梨树县| 吉林市| 灌阳县| 成武县| 仁怀市| 宁德市| 石河子市| 阳江市| 安岳县| 泸西县| 临西县| 台北市| 惠东县| 武邑县| 凤城市| 镇原县| 武夷山市| 营山县| 伊春市| 盖州市| 饶阳县| 沙河市| 大同市| 阿拉尔市| 阿拉善左旗| 广宗县| 富蕴县| 个旧市| 洛川县| 碌曲县| 通州区| 华池县| 临颍县| 南开区| 蕉岭县| 基隆市| 尉氏县| 名山县| 科尔|