1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        MybatisPlus 使用 saveOrUpdate() 方法踩坑記錄(慎用)

        共 6606字,需瀏覽 14分鐘

         ·

        2022-11-02 02:08

        點(diǎn)擊上方藍(lán)色字體,選擇“設(shè)為星標(biāo)”


        回復(fù)”學(xué)習(xí)資料“獲取學(xué)習(xí)寶典


        今天的想法是,要在插入數(shù)據(jù)庫(kù)時(shí),如果有某某一個(gè)主要字段的值重復(fù),則不插入,否則則插入!看了一下mybatis-Plus是有這個(gè)saveOrUpdate 方法!

        原本使用save時(shí)是沒(méi)有問(wèn)題了,改成saveOrUpdate 用了一下就報(bào)錯(cuò)了。

        com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: error: can not execute. because can not find column for id from entity!

        就是這個(gè)mybatisPlus不能找到哪個(gè)是主鍵字段,因?yàn)檫@個(gè)saveOrUpdate默認(rèn)是根據(jù)主鍵執(zhí)行操作的!

        所有需要在原本的實(shí)體類(lèi)的主鍵頭上,打個(gè)@TableId,如下,后面是對(duì)應(yīng)數(shù)據(jù)庫(kù)的字段,已經(jīng)主鍵自動(dòng)遞增。

        @Data
        @AllArgsConstructor
        @NoArgsConstructor
        public class Subject {

          @TableId(value = "subject_Code", type = IdType.AUTO)
          private long subjectCode;

          private String subjectNameCn;

          private String subjectNameEn;

          private String subjectHref;

          private long subjectParentCode;

          private long levelCode;

          private int isDelete;

          private long operateTimestamp;


        }

        不過(guò)還有個(gè)問(wèn)題,就是這個(gè)是根據(jù)主鍵做操作的,但是我主鍵本來(lái)就是自動(dòng)遞增肯定不會(huì)有問(wèn)題的,接下來(lái)就是想個(gè)辦法,讓他根據(jù)指定字段做操作,好像是有提供了一個(gè)口子。

        // 根據(jù)updateWrapper嘗試更新,否繼續(xù)執(zhí)行saveOrUpdate(T)方法
        boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper);

        我再去看一下怎么操作的!

        研究嘗試了半天,終于搞出來(lái)了,可能是很少有人會(huì)像我這樣做吧!所以我自己嘗試了下。

        當(dāng)saveOrUpdate不使用條件構(gòu)造器時(shí),會(huì)先做根據(jù)主鍵查詢(xún),如果查出來(lái)的結(jié)果為0,那么就執(zhí)行插入操作,如果查出來(lái)的結(jié)果不為0,則執(zhí)行更新操作。

        但是一般情況下,主鍵都不會(huì)重復(fù)啊!所有我就用條件構(gòu)造器Wrapper!

        UpdateWrapper<Subject> subject_name_cn = new UpdateWrapper<Subject>()
           .eq("subject_Name_Cn", subjectNameCn);
        subjectService.saveOrUpdate(subject,subject_name_cn );

        這樣改變后的結(jié)果就是會(huì)先執(zhí)行修改,如果執(zhí)行一條,則執(zhí)行成功,如果執(zhí)行結(jié)果為0,再執(zhí)行根據(jù)主鍵查詢(xún),然后做插入操作!

        其實(shí)有點(diǎn)多此一舉的感覺(jué),因?yàn)榧热欢家呀?jīng)更新不到結(jié)果了,那么肯定是沒(méi)有這個(gè)字段咯!

        不過(guò)轉(zhuǎn)念一想,你是指定字段沒(méi)有,又不是主鍵沒(méi)有!

        但是主鍵自增那肯定沒(méi)有??!

        所有我又想到一個(gè)騷操作,我不傳UpdateWrapper而傳QueryWrapper會(huì)怎么樣呢!

        會(huì)不會(huì)加在查詢(xún)條件種呢!我丟進(jìn)去沒(méi)有報(bào)錯(cuò),有點(diǎn)小激動(dòng),不知道結(jié)果如何!

        QueryWrapper<Subject> subject_name_cn1 = new QueryWrapper<Subject>()
                            .eq("subject_Name_Cn", subjectNameCn);
        subjectService.saveOrUpdate(subject,subject_name_cn1);

        好吧!上來(lái)全給我Update了!絲毫不留情面!我把數(shù)據(jù)刪了再試試!

        好吧!然并卵!幻想破滅!跟傳UpdateWrapper沒(méi)有區(qū)別!~告辭!

        看了一下源碼,默認(rèn)參數(shù)是Wrapper類(lèi)型,然后根據(jù)條件構(gòu)造器更新,成功則返回,不成功則走無(wú)條件構(gòu)造器的方法。

        default boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper) {
            return this.update(entity, updateWrapper) || this.saveOrUpdate(entity);
        }

        我感覺(jué)應(yīng)該加個(gè)類(lèi)型判斷!

         if(updateWrapper instanceof QueryWrapper){
          //去拼接查詢(xún)語(yǔ)句!
         }
          if(updateWrapper instanceof UpdateWrapper){
          //去拼接更新語(yǔ)句!
         }

        這樣就不會(huì)只根據(jù)ID來(lái)死查了!

        為什么要用updateWrapper?

        它與queryWrapper的區(qū)別就是:updateWrapper用set來(lái)設(shè)置修改的數(shù)據(jù);queryWrapper應(yīng)用select來(lái)設(shè)置要查出來(lái)的數(shù)據(jù)。

        saveOrUpdate 是否有映射id

        我們知道m(xù)ybatis在插入時(shí),會(huì)映射id,但是如果是saveOrUpdate會(huì)怎么樣呢?

        比如我saveOrUpdate()后,需要用他的id,但是我傳進(jìn)去的對(duì)象是沒(méi)有id的。

         @Test
         void saveOrUpdate(){
               UserText userText = new UserText();
               userText.setUserSex(Sex.MAN);
               boolean b = userTextService.saveOrUpdate(userText);
               System.out.println(userText.getUserId());
           }

        可以看到他先通過(guò)id查了沒(méi)有再進(jìn)行插入,然后返回新的id。

        ==>  Preparing: SELECT user_id,user_name,user_sex,start_time FROM user_text WHERE user_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: INSERT INTO user_text ( user_sex ) VALUES ( ? )
        ==> Parameters: 1(Integer)
        <==    Updates: 1

        不過(guò)這個(gè)update,不用試我都感覺(jué)難搞,因?yàn)槟闳绻麤](méi)有id,那么你傳入這個(gè)對(duì)象的值,可能查出多個(gè)對(duì)象,那么他要把哪個(gè)id映射回來(lái),是吧!

        @Test
        void saveOrUpdate(){
             UserText userText = new UserText();
             userText.setUserSex(Sex.MAN);
             UpdateWrapper<UserText> objectUpdateWrapper = new UpdateWrapper<UserText>()
                     .eq("user_sex",Sex.MAN);
             boolean b = userTextService.saveOrUpdate(userText,objectUpdateWrapper);
             System.out.println(userText.getUserId());
         }

        但還是試一下,當(dāng)我們加了一個(gè)UpdateWrapper后,有執(zhí)行成功,執(zhí)行了3條,返回了id為0。

        但是這次加了wrapper,我再試試如果只插入一條,會(huì)怎么樣。哈哈,不去讀源碼去debug,就只能這樣試試了,莫怪。

        誒,對(duì)啊,我去看看源碼先,看能不能看出什么門(mén)道。

        之前好像也有看了點(diǎn)源碼。兩種不同構(gòu)造的方法,執(zhí)行的邏輯也不一樣。

        boolean saveOrUpdate(T entity)

        default boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper) {
         return this.update(entity, updateWrapper) || this.saveOrUpdate(entity);
        }

        區(qū)別不大,就是會(huì)多執(zhí)行一步更新,如果執(zhí)行成功就直接走,執(zhí)行不成功再根據(jù)這個(gè)對(duì)象做saveOrUpdate。

        進(jìn)去翻了翻就是,如果通過(guò)id查到值,就根據(jù)id更新,不然就做新增。

        所以也就不用試了,還是自己手寫(xiě)一個(gè)吧,如果需要返回id的話(huà)。

        慎用!

        細(xì)思極恐,當(dāng)你是主鍵自動(dòng)生成的數(shù)據(jù),一定要寫(xiě)UpdateWrapper,不然你必然是一直插入!完全不會(huì)更新,因?yàn)槟J(rèn)是用id查詢(xún)的。

        而主鍵生成的數(shù)據(jù),一般都不會(huì)去寫(xiě)一個(gè)id,所以?。≮s快看看吧!

        UpdateWrapper 小貼士

        上面雖然寫(xiě)了updateWrapper可以寫(xiě)一個(gè)set屬性,有兩種情況。

        首先,我們一個(gè)對(duì)象,有5條屬性,只有4條有值,1條沒(méi)有值。

        mybatis-plus在執(zhí)行時(shí),會(huì)先去看看你的對(duì)象哪條屬性有值,哪條沒(méi)有。

        只會(huì)更新有值的屬性,所以只會(huì)更新4個(gè)屬性,另外一個(gè)屬性并不會(huì)把他置空。

        后續(xù)

        我發(fā)現(xiàn)一個(gè)很垃圾的,前面我吹的那個(gè)updateWrapper的set多牛逼,其實(shí)是我想的太美了,他只是在原本的基礎(chǔ)上再加一個(gè)字段!我吐了!

        UpdateWrapper<GameScorePo> updateWrapper = new UpdateWrapper<GameScorePo>()
                           .eq("game_id",gameScorePo.getGameId())
                           .eq("team_id",gameScorePo.getTeamId())
                           .eq("quarter",gameScorePo.getQuarter())
                           .set("score",gameScorePo.getScore());

                   gameScoreService.saveOrUpdate(gameScorePo,updateWrapper);

        這樣的執(zhí)行結(jié)果是這樣的!

        兩個(gè)score,我吐了!

        難道是我打開(kāi)的姿勢(shì)不對(duì)?

        查了一下知道這個(gè)set怎么樣了

        就是不要丟對(duì)象,丟一個(gè)空的對(duì)象,這樣就能set了!

        單獨(dú)的set好用,但是用在saveOrUpdate就不好用咯!看自己的需求走吧!

        感謝閱讀,希望對(duì)你有所幫助 :) 

        來(lái)源:blog.csdn.net/weixin_45369440/article/details/116044771


        -------------  END  -------------
        掃描下方二維碼,加入技術(shù)群。暗號(hào):加群

        瀏覽 74
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            羞耻拉开双腿打光屁屁撅高 | 三上悠亚被狂c躁到高潮失禁 | 免费男阳茎伸入女阳道视频 | 看国产毛片 | 国产乱码精品一区二三赶尸艳谈 | 国产传媒操逼视频 | 黄污涩涩啪啪www免费下载 | 黑人大鸡吧 | 艹逼视频无码 | 操妞网 |