<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          告警:MyBatis-Plus中慎用@Transactional注解,坑的差點被開了...

          共 4152字,需瀏覽 9分鐘

           ·

          2023-08-09 00:31

          昨天測試說有個 xx 功能用不了,扔給我一個截圖,說有報錯:

          報錯信息就是:Transaction rolled back because it has been marked as rollback-only,很好理解:事務被回滾了,因為它已經被標記了只能回滾。

          我一看巧了,這不就是我之前分析過的面試題嗎!

          之前的文章我解釋過:這種錯一般發(fā)生在嵌套事務中,即內層事務出錯,但是由于是否提交事務的操作由外層事務觸發(fā),于是乎內層事務只能做個標記,來設置當前事務只能回滾。

          緊接著它想拋出錯誤,但是由于被 try catch 了,于是乎正常執(zhí)行后續(xù)的邏輯,等執(zhí)行到最后,外層要提交事務了,發(fā)現(xiàn)當前事務已經被打了回滾的標記,所以提交失敗,報了上面的錯。

          問題重現(xiàn)

          具體原理可以看我之前的那篇文章,這里簡單舉例下會出錯的示例代碼:

          大致就是下面這個代碼調用邏輯,有一個 service 標記了 @Transcational,采用默認的事務傳播機制:

          緊接著 UserService#insert 調用了 addressService#errorInvoker,這個方法也標記了 @Transcational:

          這樣一來,只要 addressService#errorInvoker 的調用發(fā)生報錯,那么必然能重現(xiàn)上面的報錯信息。

          原理很清晰,我不可能犯這個錯。

          我信誓旦旦的對測試說:這肯定是老陳寫的 bug,與我無關!

          老陳瞄了我一眼:老子已經 2 個月沒碰過那個項目了,你扯犢子呢?

          隨后這個老測試直接把更詳細的報錯扔了過來,咳咳,涉及公司的類名這里不展示的,反正確實是我的代碼....

          但是我還是覺得很不可思議,這部分邏輯是我新寫的,我壓根就沒有使用嵌套事務啊!

          大致的代碼如下:

          @Override
          @Transactional(rollbackFor = Exception.class)
          public Boolean xxx(xxx dto
          {
              list1 = .....;
              try {
                    數據庫批量保存list1;
              } catch (Exception e) {
                  if (e instanceof DuplicateKeyException) {
                      //篩選過濾重復 key 的數據
                      //打標發(fā)送
                      數據庫批量保存過濾之后的list1;
                  }
                  ....
              }
              sendToMQ(xxx);
              list2 = .....;
              try {
                   數據庫批量保存list2;
              } catch (Exception e) {
                  if (e instanceof DuplicateKeyException) {
                      //篩選過濾重復 key 的數據
                      //打標發(fā)送
                      數據庫批量保存過濾之后的list2;
                  }
                  ...
              }
              sendToMQ(xxx);
              return Boolean.TRUE;
          }

          這個接口其實是一次性接口,用來補數據的,線上跑過一次后,后面應該不會再使用。

          出于保險原則,兼容上游部分數據重復調用,所以我做了重復key的處理,剔除重復的部分,讓不重復的部分正常保存。

          正常情況下不會出現(xiàn)這個場景,剛好測試環(huán)境測試來回折騰有很多重復數據(其實我這樣寫也是為了兼容測試,隨便他折騰)

          這里的代碼邏輯不復雜,明面上來看,我并沒有調用別的 service !也并不存在嵌套事務的問題,所以我思來想去也看不明白。

          于是......

          我出門放了個水,順帶逛了一圈,接著買了杯咖啡,遇事不決,量子力...個屁,立馬屁顛屁顛的跑回來繼續(xù)看代碼。

          回來突然就看 try-catch 不爽。

          但是 try 里面就是一個  mybatis-plus 的 IService,批量保存數據的操作。

          難道它有什么騷操作?點進去一看突然發(fā)現(xiàn):

          我丟!

          喚起了我的記憶,mybatis-plus 為了保證批量保存的事務性,加了 @Transactional。

          合著我確實沒想著使用嵌套事務,但是這被迫上了“賊船”??!

          這本是好意,但是在我這個場景有點麻,它完美的復現(xiàn)了上文提到的那個錯誤使用,在有重復 key 的場景確實報錯了,但是被外層 try-catch 攔住了拋錯,不過事務上已經打了失敗的標了!

          解決方案

          解決辦法其實很簡單:

          1. 把 saveBatch 上的 @Transactional 注解刪了,很明顯我做不到,這是 mybatisplus 的源碼。
          2. 把 saveBatch 上的 @Transactional 注解上設置事務傳播機制為:REQUIRES_NEW 或 NESTED,很明顯,我也做不到,這是 mybatis-plus 的源碼。

          然后我找了下,好像也沒有什么參數可以指定 saveBatch 的事務傳播機制。

          所以咋辦。。。測試還在催我,沒辦法,只能不用 mybatis-plus 的 saveBatch ,自己通過 mapper 寫個批量插入了:

          一波操作提交代碼重啟服務,讓測試再試試,且輕飄飄的甩一句:這不是我的bug,我被框架坑了。

          咳咳,反正我不管,我的代碼沒有bug,這是程序員最后的倔強。

          最后

          所以在使用三方代碼的情況下還是需要多留個心眼點點看。

          我記得以前還聽說過一個段子,就是有個人用了一個網上的組件,正常情況下都沒事,異常情況下,系統(tǒng)就掛了。

          后面一找,那個組件在個角落嘎達寫了 System.exit

               

          程序汪資料鏈接

          程序汪接的7個私活都在這里,經驗整理

          Java項目分享  最新整理全集,找項目不累啦 07版

          堪稱神級的Spring Boot手冊,從基礎入門到實戰(zhàn)進階

          臥槽!字節(jié)跳動《算法中文手冊》火了,完整版 PDF 開放下載!

          臥槽!阿里大佬總結的《圖解Java》火了,完整版PDF開放下載!

          字節(jié)跳動總結的設計模式 PDF 火了,完整版開放下載!

          歡迎添加程序汪個人微信 itwang007  進粉絲群或圍觀朋友圈

          瀏覽 6259
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美精品久久久久久久久 | 看全色黄大色大片 | 国产精品久久久久久免费免熟 | 狠狠撸天天撸 | 亚洲男女操逼 |