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

Spring事務(wù)管理中的“Rollback-only”問題分析與解決方案

 更新時(shí)間:2025年07月09日 08:53:28   作者:碼農(nóng)阿豪@新空間  
在Spring框架開發(fā)中,事務(wù)管理是保證數(shù)據(jù)一致性的關(guān)鍵機(jī)制,然而,嵌套事務(wù)或異常處理不當(dāng)可能導(dǎo)致UnexpectedRollbackException,并伴隨錯(cuò)誤提示Rollback-only,本文通過一個(gè)實(shí)際案例分析問題根源,并提供多種解決方案,需要的朋友可以參考下

引言

在Spring框架開發(fā)中,事務(wù)管理是保證數(shù)據(jù)一致性的關(guān)鍵機(jī)制。然而,嵌套事務(wù)或異常處理不當(dāng)可能導(dǎo)致UnexpectedRollbackException,并伴隨錯(cuò)誤提示:“Transaction silently rolled back because it has been marked as rollback-only”。

本文通過一個(gè)實(shí)際案例(郵件發(fā)送失敗觸發(fā)事務(wù)回滾),分析問題根源,并提供多種解決方案。同時(shí),探討如何優(yōu)化事務(wù)設(shè)計(jì),避免類似問題。

1. 問題背景

1.1 錯(cuò)誤日志

在調(diào)度任務(wù)執(zhí)行時(shí),日志報(bào)錯(cuò)如下:

2025-07-07 16:37:42.269 ERROR c.m.o.s.c.impl.MonitorServiceImpl - 零乙-shuying郵件發(fā)送失敗
2025-07-07 16:37:42.270 ERROR o.s.s.s.TaskUtils$LoggingErrorHandler - Unexpected error occurred in scheduled task
org.springframework.transaction.UnexpectedRollbackException: 
    Transaction silently rolled back because it has been marked as rollback-only

1.2 核心問題

  • 郵件發(fā)送失敗后,事務(wù)被標(biāo)記為rollback-only,但外部事務(wù)嘗試提交時(shí)被強(qiáng)制回滾。
  • 導(dǎo)致整個(gè)調(diào)度任務(wù)失敗,影響后續(xù)業(yè)務(wù)流程。

2. 代碼分析

2.1 事務(wù)方法定義

以下是一個(gè)監(jiān)控告警服務(wù),根據(jù)P99延遲觸發(fā)電話、短信或郵件通知:

@Override
@Transactional(rollbackFor = Exception.class)
public void p99Inform(ChannelMonitorDataVo channelMonitorDataVos, QueryMonitorDataForm queryMonitorDataForm) {
    // 1. 檢查P99延遲
    if (max >= 2000) {
        try {
            // 調(diào)用郵件服務(wù)(嵌套事務(wù))
            emailService.sendSimpleMail(agentId.toString(), email, "P99告警", "請(qǐng)?zhí)幚?);
            // 記錄通知日志(DB操作)
            sysNotifyRecordMapper.insertRecord(record);
        } catch (Exception e) {
            log.error("郵件發(fā)送失敗", e); // 捕獲異常但未拋出
        }
    }
}

2.2 郵件服務(wù)實(shí)現(xiàn)

郵件服務(wù)獨(dú)立事務(wù),失敗時(shí)拋出異常:

@Override
@Transactional // 默認(rèn)REQUIRED傳播行為
public void sendSimpleMail(String companyCode, String to, String subject, String text) {
    try {
        mailSender.send(message);
    } catch (MailException e) {
        throw new RuntimeException("郵件發(fā)送失敗"); // 觸發(fā)回滾
    }
}

3. 問題根源

3.1 嵌套事務(wù)傳播機(jī)制

  • 默認(rèn)傳播行為(REQUIRED):
    當(dāng)p99Inform()調(diào)用sendSimpleMail()時(shí),兩者共享同一個(gè)事務(wù)。
    • 若郵件發(fā)送失敗,內(nèi)部事務(wù)標(biāo)記為rollback-only。
    • 外部事務(wù)嘗試提交時(shí),Spring檢測(cè)到不一致,強(qiáng)制回滾整個(gè)事務(wù)。

3.2 異常處理矛盾

  • p99Inform()捕獲了異常,但sendSimpleMail()拋出異常,導(dǎo)致事務(wù)狀態(tài)沖突。

3.3 事務(wù)邊界不合理

  • 非核心操作(如郵件發(fā)送)與DB操作共用事務(wù),局部失敗影響全局。

4. 解決方案

4.1 方案1:調(diào)整事務(wù)傳播行為

讓郵件服務(wù)使用獨(dú)立事務(wù)(REQUIRES_NEW):

@Override
@Transactional(propagation = Propagation.REQUIRES_NEW) // 獨(dú)立事務(wù)
public void sendSimpleMail(String companyCode, String to, String subject, String text) {
    // 邏輯不變
}

優(yōu)點(diǎn):郵件發(fā)送失敗不會(huì)回滾主事務(wù)。
缺點(diǎn):獨(dú)立事務(wù)開銷略高。

4.2 方案2:統(tǒng)一異常處理

p99Inform()中不拋出異常:

try {
    emailService.sendSimpleMail(...);
} catch (Exception e) {
    log.error("郵件發(fā)送失敗,但不影響主流程", e); // 僅記錄,不拋出
}

適用場景:郵件通知是非關(guān)鍵路徑。

4.3 方案3:移除事務(wù)注解

如果郵件發(fā)送無需事務(wù):

@Override // 無@Transactional
public void sendSimpleMail(...) {
    // 直接發(fā)送郵件
}

5. 優(yōu)化建議

5.1 事務(wù)粒度控制

  • 核心操作:DB寫入使用事務(wù)。
  • 非核心操作:通知、日志等異步或非事務(wù)處理。

5.2 異常分類處理

// 業(yè)務(wù)異常(不觸發(fā)回滾)
public class BusinessException extends RuntimeException {}

// 系統(tǒng)異常(觸發(fā)回滾)
public class SystemException extends RuntimeException {}

@Transactional
public void execute() {
    try {
        emailService.send();
    } catch (BusinessException e) {
        log.warn("業(yè)務(wù)異常,繼續(xù)執(zhí)行");
    }
}

5.3 Redis操作原子化

使用increment替代get+put

redisTemplate.opsForHash().increment(redisKey, redisHashKey, 1);

5.4 日志完善

記錄完整異常堆棧:

catch (Exception e) {
    log.error("郵件發(fā)送失敗: company={}, to={}", companyCode, to, e);
}

6. 總結(jié)

方案適用場景優(yōu)缺點(diǎn)
調(diào)整傳播行為(REQUIRES_NEW)需保證郵件發(fā)送獨(dú)立回滾事務(wù)隔離性好,但開銷略高
統(tǒng)一異常處理郵件失敗不影響主流程簡單,但需明確業(yè)務(wù)優(yōu)先級(jí)
移除事務(wù)注解郵件發(fā)送無需事務(wù)性能最優(yōu),但失去事務(wù)保障

最終建議:

  • 關(guān)鍵業(yè)務(wù)(如支付)優(yōu)先選擇 方案1(REQUIRES_NEW)。
  • 非關(guān)鍵通知(如日志)選擇 方案2 或 方案3。

通過合理設(shè)計(jì)事務(wù)邊界和異常處理,可以有效避免rollback-only問題,提升系統(tǒng)健壯性。

以上就是Spring事務(wù)管理中的“Rollback-only”問題分析與解決方案的詳細(xì)內(nèi)容,更多關(guān)于Spring Rollback-only問題的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • java實(shí)現(xiàn)ftp上傳 如何創(chuàng)建文件夾

    java實(shí)現(xiàn)ftp上傳 如何創(chuàng)建文件夾

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)ftp上傳的相關(guān)資料,教大家如何創(chuàng)建文件夾?具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • 使用Java實(shí)現(xiàn)5種負(fù)載均衡算法實(shí)例

    使用Java實(shí)現(xiàn)5種負(fù)載均衡算法實(shí)例

    負(fù)載均衡指由多臺(tái)服務(wù)器以對(duì)稱的方式組成一個(gè)服務(wù)器集合,每臺(tái)服務(wù)器都具有等價(jià)的地位,都可以單獨(dú)對(duì)外提供服務(wù)而無須其他服務(wù)器的輔助,這篇文章主要給大家介紹了關(guān)于使用Java實(shí)現(xiàn)5種負(fù)載均衡算法的相關(guān)資料,需要的朋友可以參考下
    2021-09-09
  • apllo開源分布式配置中心詳解

    apllo開源分布式配置中心詳解

    這篇文章主要為大家介紹了apllo開源分布式配置中心部署詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-02-02
  • SpringBoot3.x打包Docker容器的實(shí)現(xiàn)

    SpringBoot3.x打包Docker容器的實(shí)現(xiàn)

    這篇文章主要介紹了SpringBoot3.x打包Docker容器的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-11-11
  • Spring的@Scheduled 如何動(dòng)態(tài)更新cron表達(dá)式

    Spring的@Scheduled 如何動(dòng)態(tài)更新cron表達(dá)式

    這篇文章主要介紹了Spring的@Scheduled 如何動(dòng)態(tài)更新cron表達(dá)式的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • springboot實(shí)現(xiàn)配置文件關(guān)鍵信息加解密

    springboot實(shí)現(xiàn)配置文件關(guān)鍵信息加解密

    在項(xiàng)目配置文件中常常會(huì)配置如數(shù)據(jù)庫連接信息,redis連接信息等,連接密碼明文配置在配置文件中會(huì)很不安全,所以本文就來聊聊如何使用springboot實(shí)現(xiàn)配置文件關(guān)鍵信息加解密吧
    2025-05-05
  • Java二分查找算法實(shí)例詳解

    Java二分查找算法實(shí)例詳解

    在本篇文章里小編給大家分享總結(jié)的是一篇關(guān)于Java二分查找算法實(shí)例詳解內(nèi)容,對(duì)此有興趣的朋友們可以跟著學(xué)習(xí)下。
    2022-11-11
  • Java實(shí)現(xiàn)map轉(zhuǎn)換成json的方法詳解

    Java實(shí)現(xiàn)map轉(zhuǎn)換成json的方法詳解

    這篇文章主要為大家詳細(xì)介紹了Java語言實(shí)現(xiàn)map轉(zhuǎn)換成json的幾種方法,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Java有一定幫助,需要的可以參考一下
    2022-05-05
  • JDK1.7的ConcurrentHashMap源碼解析

    JDK1.7的ConcurrentHashMap源碼解析

    這篇文章主要介紹了JDK1.7的ConcurrentHashMap源碼解析,HashMap是非線程安全的,而HashTable是線程安全的,但是HashTable實(shí)現(xiàn)同步的方法比較暴力,即在所有的方法體上添加synchronized關(guān)鍵字,需要的朋友可以參考下
    2023-12-12
  • java ssm框架實(shí)現(xiàn)分頁功能的示例代碼(oracle)

    java ssm框架實(shí)現(xiàn)分頁功能的示例代碼(oracle)

    這篇文章主要介紹了java ssm框架實(shí)現(xiàn)分頁功能的示例代碼(oracle),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-03-03

最新評(píng)論

电白县| 滕州市| 临夏县| 凤凰县| 夏河县| 探索| 东台市| 新巴尔虎右旗| 凭祥市| 林州市| 乌兰浩特市| 南通市| 四川省| 樟树市| 南靖县| 勐海县| 建德市| 肥东县| 宾川县| 米脂县| 宜丰县| 成武县| 邹平县| 绥化市| 邵武市| 珲春市| 苏尼特左旗| 灵山县| 洞头县| 屯留县| 芦山县| 砀山县| 伊宁市| 武隆县| 海盐县| 延长县| 黄石市| 焉耆| 嘉祥县| 龙井市| 镇雄县|