慎用!
UpdateWrapper 小貼士
后續
今天的想法是,要在插入數據庫時,如果有某某一個主要字段的值重復,則不插入,否則則插入!看了一下mybatis-Plus是有這個saveOrUpdate 方法!
原本使用save時是沒有問題了,改成saveOrUpdate 用了一下就報錯了。
com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: error: can not execute. because can not find column for id from entity!
就是這個mybatisPlus不能找到哪個是主鍵字段,因為這個saveOrUpdate默認是根據主鍵執行操作的!
所有需要在原本的實體類的主鍵頭上,打個@TableId,如下,后面是對應數據庫的字段,已經主鍵自動遞增。
@Data @AllArgsConstructor @NoArgsConstructor publicclassSubject{ @TableId(value="subject_Code",type=IdType.AUTO) privatelongsubjectCode; privateStringsubjectNameCn; privateStringsubjectNameEn; privateStringsubjectHref; privatelongsubjectParentCode; privatelonglevelCode; privateintisDelete; privatelongoperateTimestamp; }
不過還有個問題,就是這個是根據主鍵做操作的,但是我主鍵本來就是自動遞增肯定不會有問題的,接下來就是想個辦法,讓他根據指定字段做操作,好像是有提供了一個口子。
//根據updateWrapper嘗試更新,否繼續執行saveOrUpdate(T)方法 booleansaveOrUpdate(Tentity,WrapperupdateWrapper);
我再去看一下怎么操作的!
研究嘗試了半天,終于搞出來了,可能是很少有人會像我這樣做吧!所以我自己嘗試了下。
當saveOrUpdate不使用條件構造器時,會先做根據主鍵查詢,如果查出來的結果為0,那么就執行插入操作,如果查出來的結果不為0,則執行更新操作。
但是一般情況下,主鍵都不會重復啊!所有我就用條件構造器Wrapper!
UpdateWrappersubject_name_cn=newUpdateWrapper () .eq("subject_Name_Cn",subjectNameCn); subjectService.saveOrUpdate(subject,subject_name_cn);
這樣改變后的結果就是會先執行修改,如果執行一條,則執行成功,如果執行結果為0,再執行根據主鍵查詢,然后做插入操作!
其實有點多此一舉的感覺,因為既然都已經更新不到結果了,那么肯定是沒有這個字段咯!
不過轉念一想,你是指定字段沒有,又不是主鍵沒有!
但是主鍵自增那肯定沒有啊!
所有我又想到一個騷操作,我不傳UpdateWrapper而傳QueryWrapper會怎么樣呢!
會不會加在查詢條件種呢!我丟進去沒有報錯,有點小激動,不知道結果如何!
QueryWrappersubject_name_cn1=newQueryWrapper () .eq("subject_Name_Cn",subjectNameCn); subjectService.saveOrUpdate(subject,subject_name_cn1);
好吧!上來全給我Update了!絲毫不留情面!我把數據刪了再試試!
好吧!然并卵!幻想破滅!跟傳UpdateWrapper沒有區別!~告辭!
看了一下源碼,默認參數是Wrapper類型,然后根據條件構造器更新,成功則返回,不成功則走無條件構造器的方法。
defaultbooleansaveOrUpdate(Tentity,WrapperupdateWrapper){ returnthis.update(entity,updateWrapper)||this.saveOrUpdate(entity); }
我感覺應該加個類型判斷!
if(updateWrapperinstanceofQueryWrapper){ //去拼接查詢語句! } if(updateWrapperinstanceofUpdateWrapper){ //去拼接更新語句! }
這樣就不會只根據ID來死查了!
為什么要用updateWrapper?
它與queryWrapper的區別就是:updateWrapper用set來設置修改的數據;queryWrapper應用select來設置要查出來的數據。
saveOrUpdate 是否有映射id
我們知道mybatis在插入時,會映射id,但是如果是saveOrUpdate會怎么樣呢?
比如我saveOrUpdate()后,需要用他的id,但是我傳進去的對象是沒有id的。
@Test voidsaveOrUpdate(){ UserTextuserText=newUserText(); userText.setUserSex(Sex.MAN); booleanb=userTextService.saveOrUpdate(userText); System.out.println(userText.getUserId()); }
可以看到他先通過id查了沒有再進行插入,然后返回新的id。
==>Preparing:SELECTuser_id,user_name,user_sex,start_timeFROMuser_textWHEREuser_id=? ==>Parameters:0(Long) <==??????Total:?0 Releasing?transactional?SqlSession?[org.apache.ibatis.session.defaults.DefaultSqlSession@6d0fe80c] Fetched?SqlSession?[org.apache.ibatis.session.defaults.DefaultSqlSession@6d0fe80c]?from?current?transaction ==>Preparing:INSERTINTOuser_text(user_sex)VALUES(?) ==>Parameters:1(Integer) <==????Updates:?1
不過這個update,不用試我都感覺難搞,因為你如果沒有id,那么你傳入這個對象的值,可能查出多個對象,那么他要把哪個id映射回來,是吧!
@Test voidsaveOrUpdate(){ UserTextuserText=newUserText(); userText.setUserSex(Sex.MAN); UpdateWrapperobjectUpdateWrapper=newUpdateWrapper () .eq("user_sex",Sex.MAN); booleanb=userTextService.saveOrUpdate(userText,objectUpdateWrapper); System.out.println(userText.getUserId()); }
但還是試一下,當我們加了一個UpdateWrapper后,有執行成功,執行了3條,返回了id為0。
但是這次加了wrapper,我再試試如果只插入一條,會怎么樣。哈哈,不去讀源碼去debug,就只能這樣試試了,莫怪。
誒,對啊,我去看看源碼先,看能不能看出什么門道。
之前好像也有看了點源碼。兩種不同構造的方法,執行的邏輯也不一樣。
booleansaveOrUpdate(Tentity); defaultbooleansaveOrUpdate(Tentity,WrapperupdateWrapper){ returnthis.update(entity,updateWrapper)||this.saveOrUpdate(entity); }
區別不大,就是會多執行一步更新,如果執行成功就直接走,執行不成功再根據這個對象做saveOrUpdate。
進去翻了翻就是,如果通過id查到值,就根據id更新,不然就做新增。
所以也就不用試了,還是自己手寫一個吧,如果需要返回id的話。
慎用!
細思極恐,當你是主鍵自動生成的數據,一定要寫UpdateWrapper,不然你必然是一直插入!完全不會更新,因為默認是用id查詢的。
而主鍵生成的數據,一般都不會去寫一個id,所以啊!趕快看看吧!
基于 Spring Boot + MyBatis Plus + Vue & Element 實現的后臺管理系統 + 用戶小程序,支持 RBAC 動態權限、多租戶、數據權限、工作流、三方登錄、支付、短信、商城等功能
項目地址:https://gitee.com/zhijiantianya/ruoyi-vue-pro
視頻教程:https://doc.iocoder.cn/video/
UpdateWrapper 小貼士
上面雖然寫了updateWrapper可以寫一個set屬性,有兩種情況。
首先,我們一個對象,有5條屬性,只有4條有值,1條沒有值。
mybatis-plus在執行時,會先去看看你的對象哪條屬性有值,哪條沒有。
只會更新有值的屬性,所以只會更新4個屬性,另外一個屬性并不會把他置空。
基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 實現的后臺管理系統 + 用戶小程序,支持 RBAC 動態權限、多租戶、數據權限、工作流、三方登錄、支付、短信、商城等功能
項目地址:https://gitee.com/zhijiantianya/yudao-cloud
視頻教程:https://doc.iocoder.cn/video/
后續
我發現一個很垃圾的,前面我吹的那個updateWrapper的set多牛逼,其實是我想的太美了,他只是在原本的基礎上再加一個字段!我吐了!
UpdateWrapperupdateWrapper=newUpdateWrapper () .eq("game_id",gameScorePo.getGameId()) .eq("team_id",gameScorePo.getTeamId()) .eq("quarter",gameScorePo.getQuarter()) .set("score",gameScorePo.getScore()); gameScoreService.saveOrUpdate(gameScorePo,updateWrapper);
這樣的執行結果是這樣的!
兩個score,我吐了!
難道是我打開的姿勢不對?
查了一下知道這個set怎么樣了
就是不要丟對象,丟一個空的對象,這樣就能set了!
單獨的set好用,但是用在saveOrUpdate就不好用咯!看自己的需求走吧!
-
數據庫
+關注
關注
7文章
3845瀏覽量
64584 -
源碼
+關注
關注
8文章
652瀏覽量
29358
原文標題:MybatisPlus 使用 saveOrUpdate() 方法踩坑記錄(慎用)
文章出處:【微信號:芋道源碼,微信公眾號:芋道源碼】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論