Mybatis-Plus更新操作時(shí)遇到的問(wèn)題及解決方法
在 MyBatis-Plus開(kāi)啟邏輯刪除 的情況下,updateById更新邏輯刪除字段時(shí), “看起來(lái)執(zhí)行了但實(shí)際上沒(méi)有更新”的問(wèn)題是一種較為常見(jiàn)但不易察覺(jué)的問(wèn)題。
背景:
項(xiàng)目中使用mybatis-plus且已開(kāi)啟邏輯刪除:
mybatis-plus:
global-config:
db-config:
logic-delete-field: deleted
logic-delete-value: 1
logic-not-delete-value: 0
update-strategy: not_empty #更新策略只更新非空在代碼中獲取記錄并更新邏輯刪除字段:
useRecord record = RecordMapper.selectOne(...); record.setDeleted(1); RecordMapper.updateById(record);
執(zhí)行結(jié)果沒(méi)有明顯報(bào)錯(cuò),也不會(huì)有異常日志,但實(shí)際沒(méi)有更新邏輯刪除字段。
如果沒(méi)有記錄執(zhí)行返回值進(jìn)行判斷,將導(dǎo)致邏輯刪除失敗問(wèn)題被隱藏,為后續(xù)業(yè)務(wù)埋雷。
原因分析:
mybatis-plus使用邏輯刪除背景下,使用updateById時(shí),如下代碼段:
record.setDeleted(1); RecordMapper.updateById(record);
執(zhí)行的sql語(yǔ)句是:
UPDATE table_name SET deleted = 1 WHERE id = ? AND deleted = 0; -- ?? MyBatis-Plus 自動(dòng)添加的條件
這條 SQL 在語(yǔ)法層面是合法的,但在 MyBatis-Plus 的設(shè)計(jì)語(yǔ)義中,邏輯刪除并不被視為一次普通的 update 操作。
MyBatis-Plus 將“刪除”與“更新”在內(nèi)部邏輯上進(jìn)行了區(qū)分:updateById 被設(shè)計(jì)為只能作用于“未被邏輯刪除的數(shù)據(jù)”,而邏輯刪除本身應(yīng)通過(guò) delete 系列方法觸發(fā)。
-- 你期望生成的SQL(框架不會(huì)生成) UPDATE record SET deleted = 1 WHERE id = ? AND deleted = 0; -- updateById實(shí)際生成的SQL(deleted字段被剔除) UPDATE record SET other_field=? WHERE id = ? AND deleted = 0;
Mybatis-Plus為什么要這樣設(shè)計(jì):
MyBtis-Plus 遵循 "語(yǔ)義隔離" 原則
| 操作類(lèi)型 | 框架方法 | SQL語(yǔ)義 | 設(shè)計(jì)意圖 |
|---|---|---|---|
| 業(yè)務(wù)更新 | updateById() | 修改業(yè)務(wù)字段 | 只改數(shù)據(jù)內(nèi)容,不改數(shù)據(jù)狀態(tài) |
| 邏輯刪除 | deleteById() | UPDATE ... SET deleted=1 | 標(biāo)記數(shù)據(jù)為"已刪除"狀態(tài) |
關(guān)鍵機(jī)制:
- 攔截器過(guò)濾:LogicDeleteInterceptor 會(huì)自動(dòng)移除 SET 子句中的邏輯刪除字段
- 條件追加:所有查詢(xún)/更新操作都會(huì)自動(dòng)追加AND deleted = 0
- 單向操作:邏輯刪除被視為不可逆操作(刪除后不應(yīng)通過(guò)業(yè)務(wù)代碼恢復(fù))
如何正確處理:
- 使用 MyBatis-Plus 提供的 deleteById 進(jìn)行邏輯刪除
// 框架會(huì)自動(dòng)生成:UPDATE user SET deleted=1 WHERE id=? AND deleted=0 recordMapper.deleteById(1L);
在開(kāi)啟邏輯刪除的前提下,deleteById 不會(huì)執(zhí)行物理刪除,而是由 MyBatis-Plus 自動(dòng)生成邏輯刪除 SQL,其語(yǔ)義與框架設(shè)計(jì)完全一致。
- 用 LambdaUpdateWrapper 顯式執(zhí)行邏輯刪除
// 手動(dòng)指定SET子句,繞過(guò)字段過(guò)濾 LambdaUpdateWrapper<Record> wrapper = new LambdaUpdateWrapper<>(); wrapper.eq(Record::getId, 1L).set(Record::getDeleted, 1); // 強(qiáng)制設(shè)置deleted字段 recordMapper.update(null, wrapper);
如果業(yè)務(wù)上必須通過(guò) update 的方式完成邏輯刪除,可以使用 LambdaUpdateWrapper,自行控制 WHERE 條件,避免與 MyBatis-Plus 的自動(dòng)邏輯刪除條件產(chǎn)生沖突。此方式繞過(guò)了 updateById 的內(nèi)置邏輯刪除約束,應(yīng)明確其用途,避免被誤用為普通更新。
- 自定義 SQL 明確邏輯刪除語(yǔ)
@Update("UPDATE record SET deleted = 1 WHERE id = #{id} AND deleted = 0")
int logicDeleteById(Long id);適合對(duì)邏輯刪除行為有強(qiáng)語(yǔ)義要求的項(xiàng)目,便于代碼閱讀和后期維護(hù)。
總結(jié):
在 MyBatis-Plus 中,邏輯刪除不是一次普通的字段更新操作。updateById 被設(shè)計(jì)為只能更新“未被邏輯刪除的數(shù)據(jù)”,而不用于觸發(fā)邏輯刪除本身。當(dāng)更新語(yǔ)句同時(shí)在 SET 和 WHERE 中涉及邏輯刪除字段時(shí),就會(huì)與框架的設(shè)計(jì)語(yǔ)義產(chǎn)生沖突。正確的做法是使用 delete 系列方法,或通過(guò) Wrapper / 自定義 SQL 明確表達(dá)“邏輯刪除”的意圖。
到此這篇關(guān)于Mybatis-Plus更新操作時(shí)的一個(gè)坑的文章就介紹到這了,更多相關(guān)Mybatis-Plus更新操作時(shí)的一個(gè)坑內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Intellij IDEA中如何查看maven項(xiàng)目中所有jar包的依賴(lài)關(guān)系圖
這篇文章主要介紹了Intellij IDEA中如何查看maven項(xiàng)目中所有jar包的依賴(lài)關(guān)系圖,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05
java實(shí)現(xiàn)RedisTemplate操作哈希數(shù)據(jù)
RedisTemplate是Spring Data Redis提供的一個(gè)用于操作Redis的模板類(lèi),本文主要介紹了java實(shí)現(xiàn)RedisTemplate操作哈希數(shù)據(jù),具有一定的參考價(jià)值,感興趣的可以了解一下2024-09-09
Springmvc基于fastjson實(shí)現(xiàn)導(dǎo)包及配置文件
這篇文章主要介紹了Springmvc基于fastjson實(shí)現(xiàn)導(dǎo)包及配置文件,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10
Java運(yùn)行時(shí)多態(tài)性的實(shí)現(xiàn)
Java運(yùn)行時(shí)多態(tài)性的實(shí)現(xiàn)...2006-12-12
Gateway 中是否能寫(xiě) Servlet Filter
在SpringCloudGateway中不能使用ServletFilter,因?yàn)樗腔赗eactor模型構(gòu)建的,底層用的是Netty,而不是Tomcat、Jetty這些Servlet容器,要實(shí)現(xiàn)類(lèi)似功能,請(qǐng)用GlobalFilter或GatewayFilter,本文給大家解析Gateway中能寫(xiě)Servlet Filter嗎,感興趣的朋友一起看看吧2025-12-12
Java使用map實(shí)現(xiàn)帶過(guò)期時(shí)間的緩存機(jī)制
在?Java?開(kāi)發(fā)領(lǐng)域,緩存機(jī)制的構(gòu)建通常依賴(lài)于?Redis?等專(zhuān)業(yè)緩存數(shù)據(jù)庫(kù),這類(lèi)解決方案雖能提供強(qiáng)大的緩存能力,但引入中間件意味著增加系統(tǒng)架構(gòu)復(fù)雜度、部署成本與運(yùn)維負(fù)擔(dān),本文將深入探討一種輕量級(jí)替代方案基于?Java?原生Map實(shí)現(xiàn)的帶過(guò)期時(shí)間的緩存機(jī)制2025-04-04
Java語(yǔ)言基于無(wú)向有權(quán)圖實(shí)現(xiàn)克魯斯卡爾算法代碼示例
這篇文章主要介紹了Java語(yǔ)言基于無(wú)向有權(quán)圖實(shí)現(xiàn)克魯斯卡爾算法代碼示例,具有一定參考價(jià)值,需要的朋友可以了解下。2017-11-11
springboot接入方式對(duì)接股票數(shù)據(jù)源API接口的操作方法
本文介紹了如何使用Java語(yǔ)言創(chuàng)建一個(gè)項(xiàng)目來(lái)對(duì)接StockTV的API接口,包括使用HttpURLConnection或OkHttp發(fā)送HTTP請(qǐng)求,使用Java-WebSocket庫(kù)處理WebSocket連接等步驟,項(xiàng)目結(jié)構(gòu)包括添加依賴(lài)、創(chuàng)建基礎(chǔ)工具類(lèi)、實(shí)現(xiàn)股票API、外匯API等,感興趣的朋友一起看看吧2025-03-03

