自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

小心 MybatisPlus 的一個(gè)坑與面試題

開(kāi)發(fā) 前端
把 saveBatch 上的 @Transactional 注解上設(shè)置事務(wù)傳播機(jī)制為:REQUIRES_NEW 或 NESTED,很明顯,我也做不到,這是 mybatis-plus 的源碼。

本文轉(zhuǎn)載自微信公眾號(hào)「 yes的練級(jí)攻略」,作者 是Yes呀。轉(zhuǎn)載本文請(qǐng)聯(lián)系 yes的練級(jí)攻略公眾號(hào)。

你好,我是yes。

昨天測(cè)試說(shuō)有個(gè) xx 功能用不了,扔給我一個(gè)截圖,說(shuō)有報(bào)錯(cuò):

圖片

報(bào)錯(cuò)信息就是:Transaction rolled back because it has been marked as rollback-only,很好理解:事務(wù)被回滾了,因?yàn)樗呀?jīng)被標(biāo)記了只能回滾。

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

圖片

之前的文章我解釋過(guò):這種錯(cuò)一般發(fā)生在嵌套事務(wù)中,即內(nèi)層事務(wù)出錯(cuò),但是由于是否提交事務(wù)的操作由外層事務(wù)觸發(fā),于是乎內(nèi)層事務(wù)只能做個(gè)標(biāo)記,來(lái)設(shè)置當(dāng)前事務(wù)只能回滾。

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

具體原理可以看我之前的那篇文章,這里簡(jiǎn)單舉例下會(huì)出錯(cuò)的示例代碼:

大致就是下面這個(gè)代碼調(diào)用邏輯,有一個(gè) service 標(biāo)記了 @Transcational,采用默認(rèn)的事務(wù)傳播機(jī)制:

圖片

緊接著 UserService#insert 調(diào)用了 addressService#errorInvoker,這個(gè)方法也標(biāo)記了 @Transcational:

圖片

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

原理很清晰,我不可能犯這個(gè)錯(cuò)。

我信誓旦旦的對(duì)測(cè)試說(shuō):這肯定是老陳寫(xiě)的 bug,與我無(wú)關(guān)!

老陳瞄了我一眼:老子已經(jīng) 2 個(gè)月沒(méi)碰過(guò)那個(gè)項(xiàng)目了,你扯犢子呢?

隨后這個(gè)老測(cè)試直接把更詳細(xì)的報(bào)錯(cuò)扔了過(guò)來(lái),咳咳,涉及公司的類(lèi)名這里不展示的,反正確實(shí)是我的代碼....

但是我還是覺(jué)得很不可思議,這部分邏輯是我新寫(xiě)的,我壓根就沒(méi)有使用嵌套事務(wù)??!

大致的代碼如下:

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

這個(gè)接口其實(shí)是一次性接口,用來(lái)補(bǔ)數(shù)據(jù)的,線(xiàn)上跑過(guò)一次后,后面應(yīng)該不會(huì)再使用。

出于保險(xiǎn)原則,兼容上游部分?jǐn)?shù)據(jù)重復(fù)調(diào)用,所以我做了重復(fù)key的處理,剔除重復(fù)的部分,讓不重復(fù)的部分正常保存。

正常情況下不會(huì)出現(xiàn)這個(gè)場(chǎng)景,剛好測(cè)試環(huán)境測(cè)試來(lái)回折騰有很多重復(fù)數(shù)據(jù)(其實(shí)我這樣寫(xiě)也是為了兼容測(cè)試,隨便他折騰)

這里的代碼邏輯不復(fù)雜,明面上來(lái)看,我并沒(méi)有調(diào)用別的 service !也并不存在嵌套事務(wù)的問(wèn)題,所以我思來(lái)想去也看不明白。

于是......

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

回來(lái)突然就看 try-catch 不爽。

但是 try 里面就是一個(gè)  mybatis-plus 的 IService,批量保存數(shù)據(jù)的操作。

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

圖片

我丟!

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

合著我確實(shí)沒(méi)想著使用嵌套事務(wù),但是這被迫上了“賊船”啊!

這本是好意,但是在我這個(gè)場(chǎng)景有點(diǎn)麻,它完美的復(fù)現(xiàn)了上文提到的那個(gè)錯(cuò)誤使用,在有重復(fù) key 的場(chǎng)景確實(shí)報(bào)錯(cuò)了,但是被外層 try-catch 攔住了拋錯(cuò),不過(guò)事務(wù)上已經(jīng)打了失敗的標(biāo)了!

解決辦法其實(shí)很簡(jiǎn)單:

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

然后我找了下,好像也沒(méi)有什么參數(shù)可以指定 saveBatch 的事務(wù)傳播機(jī)制。

所以咋辦。。。測(cè)試還在催我,沒(méi)辦法,只能不用 mybatis-plus 的 saveBatch ,自己通過(guò) mapper 寫(xiě)個(gè)批量插入了:

圖片

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

咳咳,反正我不管,我的代碼沒(méi)有bug,這是程序員最后的倔強(qiáng)。

最后

所以在使用三方代碼的情況下還是需要多留個(gè)心眼點(diǎn)點(diǎn)看。

我記得以前還聽(tīng)說(shuō)過(guò)一個(gè)段子,就是有個(gè)人用了一個(gè)網(wǎng)上的組件,正常情況下都沒(méi)事,異常情況下,系統(tǒng)就掛了。

后面一找,那個(gè)組件在個(gè)角落嘎達(dá)寫(xiě)了 System.exit。

對(duì)上面這個(gè)錯(cuò)誤源碼層面分析有興趣的話(huà) ,可以看下我之前的這篇文章群里分享的面試題,第一題就不會(huì)了?

責(zé)任編輯:武曉燕 來(lái)源: yes的練級(jí)攻略
相關(guān)推薦

2021-03-16 08:56:35

Go interface面試

2012-08-02 09:36:58

fork面試題

2011-07-18 15:08:19

SQL存儲(chǔ)過(guò)程

2011-08-17 10:28:53

多對(duì)多查詢(xún)SQL Server

2019-08-09 09:50:38

Java編程語(yǔ)言面試題

2009-06-06 18:34:05

java面試題

2014-12-02 10:02:30

2025-03-12 08:00:00

單點(diǎn)登錄單設(shè)備登錄程序

2015-07-13 09:45:32

阿里校招

2020-06-04 14:40:40

面試題Vue前端

2024-03-12 09:34:01

2024-09-26 08:03:25

2014-09-19 11:17:48

面試題

2019-03-23 20:00:04

面試react.js前端

2023-11-13 07:37:36

JS面試題線(xiàn)程

2020-10-28 15:07:01

Arthas

2021-06-02 12:12:46

DevOps面試Linux

2011-03-24 13:27:37

SQL

2017-08-29 14:12:16

Java面試題

2015-08-27 09:27:34

JavaScript面試題
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)