MyBatis-Plus UpdateWrapper 使用常見陷阱和解決方案
概要
MyBatis-Plus是Mybatis的一個(gè)增強(qiáng),簡(jiǎn)化了Mybatis的開發(fā)過程,不僅保持了Mybatis原有的功能,而且在無代碼侵略下增加了許多的增強(qiáng)的功能,提供了豐富的CRUD操作,單表的CRUD操作幾乎無需編寫SQL語句。雖然Mybatis-Plus方便了開發(fā)者的開發(fā),但是也會(huì)遇到一些常見的陷阱和問題,了解這些潛在的陷阱并知道如何避免它們,可以幫助你更高效的和正確的使用Mybatis-Plus。本文中介紹的是UpdateWrapper的常見陷阱和對(duì)應(yīng)的解決方案。
常見陷阱與解決方案
在我們的業(yè)務(wù)場(chǎng)景中,常常需要更新多條數(shù)據(jù)。在使用 MyBatis-Plus 進(jìn)行更新操作時(shí),由于錯(cuò)誤地使用 UpdateWrapper,可能會(huì)導(dǎo)致數(shù)據(jù)更新出現(xiàn)不可預(yù)知的錯(cuò)誤。這些錯(cuò)誤包括條件重復(fù)使用、忽略邏輯刪除字段、拼寫錯(cuò)誤、以及嵌套條件使用不當(dāng)?shù)葐栴}。
用戶表
1.條件重復(fù)使用導(dǎo)致更新錯(cuò)誤
在使用Mybatis-Plus的 "UpdateWapeer" 時(shí),如果在循環(huán)中重復(fù)使用一個(gè) "UpdateWapeer" 對(duì)象,前一個(gè)循環(huán)中設(shè)置的條件和更新值會(huì)在后續(xù)的循環(huán)中繼續(xù)生效,可能會(huì)導(dǎo)致更新操作受前一次條件的影響,導(dǎo)致最終只更新了部分的數(shù)據(jù)。
假設(shè)我們有一個(gè)用戶表 'User' 需要根據(jù)不同用戶Id批量刪除用戶,采用邏輯刪除,如果我們?cè)谘h(huán)中使用同一個(gè) ‘UpdateWarpper' 對(duì)象進(jìn)行操作,就可能會(huì)導(dǎo)致部分更新錯(cuò)誤。
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); }); }
在這個(gè)錯(cuò)誤示例中,"UpdateWapeer" 在每次循環(huán)都會(huì)添加新的更新條件和設(shè)置值,導(dǎo)致前一次的條件和值影響后續(xù)的更新操作。這可能導(dǎo)致只有第一條數(shù)據(jù)被正確更新,后續(xù)的數(shù)據(jù)更新出現(xiàn)錯(cuò)誤。
解決方案
為了避免重復(fù)使用導(dǎo)致更新錯(cuò)誤,我們應(yīng)該在循環(huán)中創(chuàng)建一個(gè)新的 "UpdateWapeer" 對(duì)象,確保每次更新操作的條件和設(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ù)庫(kù),因?yàn)檫@樣每次都要?jiǎng)?chuàng)建新的連接,向Mysql發(fā)送網(wǎng)絡(luò)請(qǐng)求,增加額外的開銷。建議批量操作,這樣就連接一次數(shù)據(jù)庫(kù)就好了,性能大大的提升。
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" 對(duì)象,就能更新成功。
2.Sql注入風(fēng)險(xiǎn)
直接拼接 SQL 語句時(shí),可能會(huì)存在 SQL 注入風(fēng)險(xiǎn)。攻擊者可以通過傳入惡意構(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)造器方法,避免手動(dòng)拼接 SQL 語句,同時(shí)使用參數(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 嵌套條件時(shí),如果嵌套條件使用不當(dāng),可能會(huì)導(dǎo)致條件邏輯錯(cuò)誤,更新操作未達(dá)到預(yù)期效果。例如,條件 A and (B or C) 和 (A and B) or C 的邏輯是不同的,不正確的嵌套條件可能導(dǎo)致錯(cuò)誤的更新結(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); }
在這個(gè)錯(cuò)誤示例中,條件 lt("age", age)
和 isNull("name")
是通過 or
連接的,但沒有使用 and
進(jìn)行正確的嵌套,可能導(dǎo)致邏輯錯(cuò)誤。
解決方案
通過使用 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)致全表更新
有時(shí)候我們需要批量更新用戶的狀態(tài)。如果沒有設(shè)置任何條件,可能會(huì)導(dǎo)致全表更新,造成嚴(yán)重的后果。
public void updateAllUsersState(int state) { UpdateWrapper<User> updateWrapper = new UpdateWrapper<>(); updateWrapper.set("state", state); update(updateWrapper); }
在這個(gè)錯(cuò)誤示例中,如果未設(shè)置任何條件,可能會(huì)導(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.列名拼寫錯(cuò)誤
在使用 UpdateWrapper
時(shí),如果列名拼寫錯(cuò)誤,可能會(huì)導(dǎo)致 SQL 語法錯(cuò)誤或更新操作沒有預(yù)期效果。拼寫錯(cuò)誤會(huì)導(dǎo)致生成的 SQL 語句不正確,從而無法執(zhí)行預(yù)期的更新操作。
public void updateUserName(Long userId, String newName) { UpdateWrapper<User> updateWrapper = new UpdateWrapper<>(); updateWrapper.set("nmae", newName) // 拼寫錯(cuò)誤 .eq("id", userId); update(updateWrapper); }
解決方案
通過使用 LambdaUpdateWrapper
,可以避免列名拼寫錯(cuò)誤,因?yàn)樗褂脤?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ù)庫(kù)操作的安全性和效率,有效地防止這些問題。
到此這篇關(guān)于MyBatis-Plus UpdateWrapper 使用攻略的文章就介紹到這了,更多相關(guān)MyBatis-Plus UpdateWrapper 使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java定時(shí)任務(wù):利用java Timer類實(shí)現(xiàn)定時(shí)執(zhí)行任務(wù)的功能
本篇文章主要介紹了利用java Timer類實(shí)現(xiàn)定時(shí)執(zhí)行任務(wù)的功能,具有一定的參考價(jià)值,有需要的可以了解一下。2016-11-11Spring配置多個(gè)數(shù)據(jù)源并實(shí)現(xiàn)數(shù)據(jù)源的動(dòng)態(tài)切換功能
這篇文章主要介紹了Spring配置多個(gè)數(shù)據(jù)源并實(shí)現(xiàn)數(shù)據(jù)源的動(dòng)態(tài)切換功能,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2024-01-01java統(tǒng)計(jì)漢字字?jǐn)?shù)的方法示例
這篇文章主要介紹了java統(tǒng)計(jì)漢字字?jǐn)?shù)的方法,結(jié)合實(shí)例形式分析了java正則判定、字符串遍歷及統(tǒng)計(jì)相關(guān)操作技巧,需要的朋友可以參考下2017-05-05

SpringBoot如何使用@Aspect注解實(shí)現(xiàn)AOP

Java 數(shù)據(jù)結(jié)構(gòu)與算法系列精講之背包問題

JFinal使用ajaxfileupload實(shí)現(xiàn)圖片上傳及預(yù)覽

詳解SpringBoot結(jié)合swagger2快速生成簡(jiǎn)單的接口文檔