衡阳派盒市场营销有限公司

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Spring中事務嵌套這么用一定得注意

jf_78858299 ? 來源:JAVA旭陽 ? 作者:JAVA旭陽 ? 2023-05-11 10:50 ? 次閱讀

前言

最近項目上有一個使用事務相對復雜的業務場景報錯了。在絕大多數情況下,都是風平浪靜,沒有問題。其實內在暗流涌動,在有些異常情況下就會報錯,這種偶然性的問題很有可能就會在暴露到生產上造成事故,那究竟是怎么回事呢?

問題描述

我們用一個簡單的例子模擬下,大家也可以看看下面這段代碼輸出的結果是什么。

  1. 在類SecondTransactionService定義一個簡單接口transaction2,插入一個用戶,同時必然會拋出錯誤
@Override
@Transactional(rollbackFor = Exception.class)
public void transaction2() {
    System.out.println("do transaction2.....");
    User user = new User("tx2", "111", 18);
    // 插入一個用戶
    userService.insertUser(user);
    // 跑錯了
    throw new RuntimeException();
}
  1. 在另外一個類FirstTransactionService定義一個接口transaction1,它調用transaction2方法,同時做了try catch處理
@Override
@Transactional(rollbackFor = Exception.class)
public void transaction1() {
    System.out.println("do transaction1 .......");
    try {
        // 調用另外一個事務,try catch住
        secondTransactionService.transaction2();
    } catch (Exception e) {
        e.printStackTrace();
    }

    // 插入當前用戶tx1
    User user = new User("tx1", "111", 18);
    userService.insertUser(user);
}
  1. 定義一個controller,調用transaction1方法
@GetMapping("/testNestedTx")
public String testNestedTx() {
    firstTransactionService.transaction1();
    return "success";
}

大家覺得調用這個http接口,最終數據庫插入的是幾條數據呢?

問題結果

正確答案是數據庫插入了0條數據。

圖片

同時控制臺也報錯了,報錯原因是:org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only

圖片

是否和你預想的一樣呢?你知道是為什么嗎?

原因追溯

其實原因很簡單,我們都知道,一個事務要么全成功提交事務,要么失敗全部回滾。如果出現在一個事務中部分SQL要回滾,部分SQL要提交,這不就主打的一個”前后矛盾,精神分裂“嗎?

controller.testNestedTx() 
  || 
  / 
FirstTransactionService.transaction1()   REQUIRED隔離級別
       || 
       || 
       || 捕獲異常,提交事務,出錯啦
       / || 
FirstTransactionService.transaction2()   REQUIRED隔離級別
       || || 
       || 拋出異常,標記事務為rollback only
       =======================
  1. 事務的隔離級別為REQUIRED,那么發現沒有事務開啟一個事務操作,有的話,就合并到這個事務中,所以transaction1()、transaction2()是在同一個事務中。
  2. transaction2()拋出異常,那么事務會被標記為rollback only, 源碼如下所示:

圖片

  1. transaction1()由于try catch異常,正常運行,想必就要可以提交事務了,在提交事務的時候,會檢查rollback標記,如果是true, 這時候就會拋出上面的異常了。源碼如下圖所示:

圖片這下,是不是很清楚知道報錯的原因了,那想想該怎么處理呢?

解決之道

知道了根本原因之后,是不是解決的方案就很明朗了,我們可以通過調整事務的傳播方式分拆多個事務管理,或者讓一個事務"前后一致",做一個誠信的好事務。

  • try catch放到內層事務中,也就是transaction2()方法中,這樣內層事務會跟著外部事務進行提交或者回滾。
@Override
    @Transactional(rollbackFor = Exception.class)
    public void transaction2() {
        try {
            System.out.println("do transaction2.....");
            User user = new User("tx2", "111", 18);
            userService.insertUser2(user);
            throw new RuntimeException();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
  • 如果希望內層事務拋出異常時中斷程序執行,直接在外層事務的catch代碼塊中拋出e,這樣同一個事務就都會回滾。
  • 如果希望內層事務回滾,但不影響外層事務提交,需要將內層事務的傳播方式指定為PROPAGATION_NESTEDPROPAGATION_NESTED基于數據庫savepoint實現的嵌套事務,外層事務的提交和回滾能夠控制嵌內層事務,而內層事務報錯時,可以返回原始savepoint,外層事務可以繼續提交。

圖片

事務的傳播機制

前面提到了事務的傳播機制,我們再看都有哪幾種。

  • PROPAGATION_REQUIRED:加入到當前事務中,如果當前沒有事務,就新建一個事務。這是最常見的選擇,也是Spring中默認采用的方式。
  • PROPAGATION_SUPPORTS:支持當前事務,如果當前沒有事務,就以非事務方式執行。
  • PROPAGATION_MANDATORY :支持當前事務,如果當前沒有事務,就拋出異常。
  • PROPAGATION_REQUIRES_NEW:新建一個事務,如果當前存在事務,把當前事務掛起。
  • PROPAGATION_NOT_SUPPORTED :以非事務方式執行操作,如果當前存在事務,就把當前事務掛起。
  • PROPAGATION_NEVER: 以非事務方式執行,如果當前存在事務,則拋出異常。
  • PROPAGATION_NESTED :如果當前存在事務,則在嵌套事務內執行。如果當前沒有事務,則進行與PROPAGATION_REQUIRED類似的操作。

如何理解PROPAGATION_NESTED的傳播機制呢,和PROPAGATION_REQUIRES_NEW又有什么區別呢?我們用一個例子說明白。

  • 定義serviceA.methodA()PROPAGATION_REQUIRED修飾;
  • 定義serviceB.methodB()以表格中三種方式修飾;
  • methodA中調用methodB;

圖片

總結

在我的項目中之所以會報“rollback-only”異常的根本原因是代碼風格不一致的原因。外層事務對錯誤的處理方式是返回true或false來告訴上游執行結果,而內層事務是通過拋出異常來告訴上游(這里指外層事務)執行結果,這種差異就導致了“rollback-only”異常。大家也可以去review自己項目中的代碼,是不是也偷偷犯下同樣的錯誤了。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 接口
    +關注

    關注

    33

    文章

    8691

    瀏覽量

    151920
  • 代碼
    +關注

    關注

    30

    文章

    4827

    瀏覽量

    69054
  • spring
    +關注

    關注

    0

    文章

    340

    瀏覽量

    14390
收藏 人收藏

    評論

    相關推薦

    Spring事務失效的十種常見場景

    Spring針對Java Transaction API (JTA)、JDBC、Hibernate和Java Persistence API(JPA)等事務 API,實現了致的編程模型,而
    的頭像 發表于 12-11 15:03 ?957次閱讀

    Spring事務實現原理

    作者:京東零售 范錫軍 1、引言 springspring-tx模塊提供了對事務管理支持,使用spring事務可以讓我們從復雜的
    的頭像 發表于 11-08 10:10 ?874次閱讀
    <b class='flag-5'>Spring</b><b class='flag-5'>事務</b>實現原理

    什么是java spring

    。在SSH項目中管理事務以及對象的注入Spring是非侵入式的:基于Spring開發的系統的對象般不依賴于
    發表于 09-11 11:16

    Spring的兩種方式事務管理和API接口介紹

    Spring事務管理
    發表于 03-21 06:52

    Spring事務分析的實現方式

    Spring事務原理分析
    發表于 07-02 15:19

    詳解Spring事務管理

    在學習spring事務管理時,我忍不住要問,spring為什么進行事務管理,spring怎么進行的事務
    發表于 07-12 06:54

    Spring事務管理詳解說明

    Spring事務管理詳解
    發表于 05-20 13:46

    spring聲明式事務實現原理猜想

    ? @Transactional注解簡介 @Transactional 是spring聲明式事務管理的注解配置方式,相信這個注解的作用大家都很清楚。 @Transactional 注解可以幫助
    的頭像 發表于 10-13 09:20 ?1664次閱讀

    淺談Spring事務的那些坑

    對于從事java開發工作的同學來說,spring事務肯定再熟悉不過了。在某些業務場景下,如果同時有多張表的寫入操作,為了保證操作的原子性(要么同時成功,要么同時失敗)避免數據不致的情況,我們
    的頭像 發表于 10-11 10:31 ?775次閱讀

    發現Spring事務的巨坑bug 你必須要小心了

    不正確 9.多線程調用 10.嵌套事務多回滾了 對于從事java開發工作的同學來說,spring事務肯定再熟悉不過了。在某些業務場景下,如果同時有多張表的寫入操作,為了保證操作的原子
    的頭像 發表于 10-11 18:17 ?896次閱讀

    淺談Spring事務底層原理

    開啟Spring事務本質上就是增加了個Advisor,但我們使用@EnableTransactionManagement注解來開啟Spring事務
    的頭像 發表于 12-06 09:56 ?731次閱讀

    Spring事務在哪幾種情況下會不生效?

    日常開發,我們經常使用到spring事務。最近星球位還有去美團面試,被問了這么道面試題:
    的頭像 發表于 05-10 17:53 ?966次閱讀
    <b class='flag-5'>Spring</b><b class='flag-5'>事務</b>在哪幾種情況下會不生效?

    8個Spring事務失效的場景介紹

    作為Java開發工程師,相信大家對Spring事務的使用并不陌生。但是你可能只是停留在基礎的使用層面上,在遇到些比較特殊的場景,事務可能沒有生效,直接在生產上暴露了,這可能就會導致
    的頭像 發表于 05-11 10:41 ?713次閱讀
    8個<b class='flag-5'>Spring</b><b class='flag-5'>事務</b>失效的場景介紹

    spring事務失效的些場景

    對于從事java開發工作的同學來說,spring事務肯定再熟悉不過了。 在某些業務場景下,如果個請求,需要同時寫入多張表的數據。為了保證操作的原子性(要么同時成功,要么同時失?。?/div>
    的頭像 發表于 10-08 14:27 ?485次閱讀
    <b class='flag-5'>spring</b><b class='flag-5'>事務</b>失效的<b class='flag-5'>一</b>些場景

    Spring事務傳播性的相關知識

    本文主要介紹了Spring事務傳播性的相關知識。
    的頭像 發表于 01-10 09:29 ?491次閱讀
    <b class='flag-5'>Spring</b><b class='flag-5'>事務</b>傳播性的相關知識
    尊龙娱乐网| 澳门百家乐大小| 百家乐官网唯一能长期赢钱的方法| 百家乐官网庄家抽水的秘密| 澳门赌百家乐官网能赢钱吗 | 太阳百家乐官网游戏| 百家乐官网打鱼秘| 做生意门口对着通道| 百家乐分路单析器| 三元玄空24山坐向| 真人百家乐作假视频| 百家乐官网baccarat| 好望角百家乐官网的玩法技巧和规则 | 百家乐007| 跪求百家乐打法| 百家乐资深 | 石景山区| 百家乐官网网上投注作弊| 百家乐官网平的概率| 百家乐官网注册赠分| 百家乐官网赌场导航| 太阳城百家乐官网外挂| 金龍百家乐官网的玩法技巧和规则 | 百家乐园36bol在线| 太阳城花园| 娱乐城送白菜| 在线百家乐官网娱乐| 百家乐官网百胜注码法| 百家乐官网德州扑克桌布| 百家乐官网网站排行| 百家乐官网双人操作分析仪| 百家乐赢家公式| 百家乐真人百家乐赌博| 顶级赌场连环夺宝下载| 卢湾区| 百家乐官网有无技巧| 百家乐看炉子的方法| 新全讯网2| 博乐百家乐官网游戏| 百家乐官网德州扑克桌布| 新全讯网2|