MyBatis-Plus UpdateWrapper 使用常見陷阱和解決方案
概要
MyBatis-Plus是Mybatis的一個增強(qiáng),簡化了Mybatis的開發(fā)過程,不僅保持了Mybatis原有的功能,而且在無代碼侵略下增加了許多的增強(qiáng)的功能,提供了豐富的CRUD操作,單表的CRUD操作幾乎無需編寫SQL語句。雖然Mybatis-Plus方便了開發(fā)者的開發(fā),但是也會遇到一些常見的陷阱和問題,了解這些潛在的陷阱并知道如何避免它們,可以幫助你更高效的和正確的使用Mybatis-Plus。本文中介紹的是UpdateWrapper的常見陷阱和對應(yīng)的解決方案。
常見陷阱與解決方案
在我們的業(yè)務(wù)場景中,常常需要更新多條數(shù)據(jù)。在使用 MyBatis-Plus 進(jìn)行更新操作時,由于錯誤地使用 UpdateWrapper,可能會導(dǎo)致數(shù)據(jù)更新出現(xiàn)不可預(yù)知的錯誤。這些錯誤包括條件重復(fù)使用、忽略邏輯刪除字段、拼寫錯誤、以及嵌套條件使用不當(dāng)?shù)葐栴}。
用戶表

1.條件重復(fù)使用導(dǎo)致更新錯誤
在使用Mybatis-Plus的 "UpdateWapeer" 時,如果在循環(huán)中重復(fù)使用一個 "UpdateWapeer" 對象,前一個循環(huán)中設(shè)置的條件和更新值會在后續(xù)的循環(huán)中繼續(xù)生效,可能會導(dǎo)致更新操作受前一次條件的影響,導(dǎo)致最終只更新了部分的數(shù)據(jù)。
假設(shè)我們有一個用戶表 'User' 需要根據(jù)不同用戶Id批量刪除用戶,采用邏輯刪除,如果我們在循環(huán)中使用同一個 ‘UpdateWarpper' 對象進(jìn)行操作,就可能會導(dǎo)致部分更新錯誤。
public void updateByIds(UserIdsPO po) {
List<Integer> userIds = po.getUserIds();
userIds.forEach(userId ->{
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
updateWrapper.set("is_delete",1)
.eq("id", userId);
update(updateWrapper);
});
}在這個錯誤示例中,"UpdateWapeer" 在每次循環(huán)都會添加新的更新條件和設(shè)置值,導(dǎo)致前一次的條件和值影響后續(xù)的更新操作。這可能導(dǎo)致只有第一條數(shù)據(jù)被正確更新,后續(xù)的數(shù)據(jù)更新出現(xiàn)錯誤。

解決方案
為了避免重復(fù)使用導(dǎo)致更新錯誤,我們應(yīng)該在循環(huán)中創(chuàng)建一個新的 "UpdateWapeer" 對象,確保每次更新操作的條件和設(shè)置值是獨(dú)立的。
public void updateByIds(UserIdsPO po) {
List<Integer> userIds = po.getUserIds();
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
userIds.forEach(userId ->{
updateWrapper.set("is_delete",1)
.eq("id", userId);
update(updateWrapper);
});
}當(dāng)然建議不要再循環(huán)中去操作數(shù)據(jù)庫,因為這樣每次都要創(chuàng)建新的連接,向Mysql發(fā)送網(wǎng)絡(luò)請求,增加額外的開銷。建議批量操作,這樣就連接一次數(shù)據(jù)庫就好了,性能大大的提升。
public void updateByIds(UserIdsPO po) {
List<Integer> userIds = po.getUserIds();
//根據(jù)用戶id查詢用戶
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.in("id", userIds);
List<User> userList = list(queryWrapper);
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
List<User> updateList = new ArrayList<>();
userList.forEach(user ->{
updateWrapper.set("is_delete",1)
.eq("id", user.getId());
//將要修改的用戶添加到集合中
updateList.add(user);
});
//批量更新
updateBatchById(updateList);
}只要確保每一次循環(huán)都是新的 "UpdateWapeer" 對象,就能更新成功。

2.Sql注入風(fēng)險
直接拼接 SQL 語句時,可能會存在 SQL 注入風(fēng)險。攻擊者可以通過傳入惡意構(gòu)造的輸入,執(zhí)行未預(yù)期的 SQL 語句,導(dǎo)致數(shù)據(jù)泄露或破壞。
public void updateUserStatus(Long userId, String status) {
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
updateWrapper.setSql("status = '" + status + "'")
.eq("id", userId);
update(updateWrapper);
}解決方案
使用 MyBatis-Plus 提供的條件構(gòu)造器方法,避免手動拼接 SQL 語句,同時使用參數(shù)化查詢來防止 SQL 注入。
public void updateUserStatus(Long userId, String status) {
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
updateWrapper.set("status", status)
.eq("id", userId);
update(updateWrapper);
}3.嵌套條件使用不當(dāng)
在使用 and 和 or 嵌套條件時,如果嵌套條件使用不當(dāng),可能會導(dǎo)致條件邏輯錯誤,更新操作未達(dá)到預(yù)期效果。例如,條件 A and (B or C) 和 (A and B) or C 的邏輯是不同的,不正確的嵌套條件可能導(dǎo)致錯誤的更新結(jié)果。
public void updateUsersState(int state, int age) {
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
updateWrapper.set("state", state);
.lt("age", age).or().isNull("name");
update(updateWrapper);
} 在這個錯誤示例中,條件 lt("age", age) 和 isNull("name") 是通過 or 連接的,但沒有使用 and 進(jìn)行正確的嵌套,可能導(dǎo)致邏輯錯誤。
解決方案
通過使用 and 方法將條件正確嵌套,確保條件 lt("age", age) 和 isNull("name") 組合在一起,并與其他條件正確連接,從而實(shí)現(xiàn)預(yù)期的更新效果。
public void updateUsersState(int state, int age) {
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
updateWrapper.set("state", state)
.and(wrapper -> wrapper.lt("age", age).or().isNull("name"));
update(updateWrapper);
}4.條件未正確設(shè)置導(dǎo)致全表更新
有時候我們需要批量更新用戶的狀態(tài)。如果沒有設(shè)置任何條件,可能會導(dǎo)致全表更新,造成嚴(yán)重的后果。
public void updateAllUsersState(int state) {
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
updateWrapper.set("state", state);
update(updateWrapper);
}在這個錯誤示例中,如果未設(shè)置任何條件,可能會導(dǎo)致全表更新。
解決方案
始終確保設(shè)置了適當(dāng)?shù)臈l件,或者在更新前進(jìn)行條件檢查。
public void updateUserStateById(Long userId, int state) {
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
updateWrapper.set("state", state)
.eq("id", userId);
update(updateWrapper);
}5.列名拼寫錯誤
在使用 UpdateWrapper 時,如果列名拼寫錯誤,可能會導(dǎo)致 SQL 語法錯誤或更新操作沒有預(yù)期效果。拼寫錯誤會導(dǎo)致生成的 SQL 語句不正確,從而無法執(zhí)行預(yù)期的更新操作。
public void updateUserName(Long userId, String newName) {
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
updateWrapper.set("nmae", newName) // 拼寫錯誤
.eq("id", userId);
update(updateWrapper);
}解決方案
通過使用 LambdaUpdateWrapper,可以避免列名拼寫錯誤,因為它使用實(shí)體類的字段而不是字符串來指定列名。
public void updateUserName(Long userId, String newName) {
LambdaUpdateWrapper<User> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
lambdaUpdateWrapper.set(User::getName, newName);
.eq(User::getId, userId);
update(lambdaUpdateWrapper);
}小結(jié)
通過避免這些潛在的問題,提高我們的數(shù)據(jù)庫操作的安全性和效率,有效地防止這些問題。
到此這篇關(guān)于MyBatis-Plus UpdateWrapper 使用攻略的文章就介紹到這了,更多相關(guān)MyBatis-Plus UpdateWrapper 使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MapStruct @Mapping注解之處理映射中的Null值方式
這篇文章主要介紹了MapStruct @Mapping注解之處理映射中的Null值方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2025-03-03
舉例講解Java設(shè)計模式編程中Decorator裝飾者模式的運(yùn)用
這篇文章主要介紹了Java設(shè)計模式編程中Decorator裝飾者模式的運(yùn)用,裝飾者模式就是給一個對象動態(tài)的添加新的功能,裝飾者和被裝飾者實(shí)現(xiàn)同一個接口,裝飾者持有被裝飾者的實(shí)例,需要的朋友可以參考下2016-05-05
利用Springboot+Caffeine實(shí)現(xiàn)本地緩存實(shí)例代碼
Caffeine是一個基于Java8開發(fā)的提供了近乎最佳命中率的高性能的緩存庫,下面這篇文章主要給大家介紹了關(guān)于利用Springboot+Caffeine實(shí)現(xiàn)本地緩存的相關(guān)資料,需要的朋友可以參考下2023-01-01
Java使用Condition實(shí)現(xiàn)精準(zhǔn)喚醒線程詳解
這篇文章主要為大家詳細(xì)介紹了Java如何使用Condition實(shí)現(xiàn)精準(zhǔn)喚醒線程效果,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起了解一下2023-02-02
如何查找YUM安裝的JAVA_HOME環(huán)境變量詳解
這篇文章主要給大家介紹了關(guān)于如何查找YUM安裝的JAVA_HOME環(huán)境變量的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2017-10-10
Spring Boot 與 Apache Pulsar 集成構(gòu)建高性能
本文介紹了ApachePulsar作為新一代消息中間件的特點(diǎn),并詳細(xì)說明了如何在SpringBoot應(yīng)用Pulsar,還介紹了Pulsar的高級特性和實(shí)踐應(yīng)用案例,如訂單處理系統(tǒng)和實(shí)時數(shù)據(jù)分析,感興趣的朋友跟隨小編一起看看吧2026-04-04

