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

@Transactional用法詳解與事務避坑指南

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

前言

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

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

一、Java的@Transactional解釋

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

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

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

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

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),為了不影響訂單正常流轉,增加一個消息中間件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服務失敗,做了個異常捕獲保存推送消息,方便重推。

三、MQ消費

// ... 其他業(yè)務邏輯 ...
        // 獲取訂單信息
        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í)行的事務邊界,確保方法內的一系列操作要么全部成功,要么全部失敗。它通常與Spring框架的事務管理器一起使用,以提供聲明式的事務管理。

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

下面是我搜到的一些可能導致該問題的原因:

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

解決方式

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

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

@Component
public class TransactionalMessageSender implements TransactionSynchronization {

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

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

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

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

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

五、總結

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

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

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

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

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

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

相關文章

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

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

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

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

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

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

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

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

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

    Java程序實現(xiàn)導出Excel的方法(支持IE低版本)

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

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

    JVM的啟動參數(shù)是在啟動JVM時可以設置的一些命令行參數(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

最新評論

项城市| 东源县| 太原市| 诸暨市| 景泰县| 阳江市| 屏山县| 屯留县| 寿光市| 潍坊市| 济宁市| 富民县| 克拉玛依市| 上饶市| 江孜县| 新源县| 延长县| 濮阳县| 内江市| 平远县| 昭苏县| 高要市| 安徽省| 林西县| 丰原市| 罗定市| 汶上县| 鹤山市| 津市市| 兴安盟| 南安市| 湖南省| 天门市| 揭阳市| 阿图什市| 固阳县| 砚山县| 容城县| 饶平县| 鹿泉市| 尚义县|