0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

MybatisPlus使用 saveOrUpdate方法踩坑记录

jf_ro2CN3Fa 来源:芋道源码 作者:芋道源码 2022-11-02 16:25 次阅读

慎用!

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);

这样的执行结果是这样的!

3be000f6-573d-11ed-a3b6-dac502259ad0.png

两个score,我吐了!

难道是我打开的姿势不对?

查了一下知道这个set怎么样了

3c03605a-573d-11ed-a3b6-dac502259ad0.png

就是不要丢对象,丢一个空的对象,这样就能set了!

单独的set好用,但是用在saveOrUpdate就不好用咯!看自己的需求走吧!

审核编辑:彭静
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 数据库
    +关注

    关注

    7

    文章

    3752

    浏览量

    64220
  • 源码
    +关注

    关注

    8

    文章

    632

    浏览量

    29108

原文标题:MybatisPlus 使用 saveOrUpdate() 方法踩坑记录(慎用)

文章出处:【微信号:芋道源码,微信公众号:芋道源码】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    【STM32+机智云】机智云手机APP点灯实验记录 精选资料分享

    【STM32+机智云】机智云手机APP点灯实验记录一、实验背景因为项目开发需要用到云平台,所以开始学习机智云平台,听说机智云比较容易入门,还有手机APP。因此开始了
    发表于 08-04 08:30

    开发STM32 USB HID过的

    记录一下 开发STM32 USB HID过的一、前言二、代码配置一、前言MCU: STM32F103C8T6CubeMX: STM32CubeMX 5.3.0二、代码配置引脚配置时钟树配置我
    发表于 08-24 07:15

    使用树莓派搭建stm32开发环境过的以及碰到的问题

    使用树莓派搭建stm32开发环境了很多,下面主要是记录一下过的,以及碰到的问题。##开发方式的选择1.使用Eclipse+GDB+O
    发表于 08-24 07:47

    NodeMCU开发板经历分享

    写在前面今天入手了一个NodeMCU的板子,准备学习一下物联网相关的知识。不过由于博主学艺不精,在第一步烧写固件上就了,所以就想着把自己的经历写出来分享给大家,希望能有一些帮助
    发表于 11-01 07:55

    Linux学习过程过的与如何解决

    Linux记录记录Linux学习过程过的与如何解决
    发表于 11-04 08:44

    STM32编程常有哪些?

    STM32编程常有哪些?
    发表于 12-17 06:15

    Xavier入门PWM问题解决方法

    Xavier入门PWM问题解决方法GPIO问题解决方法PWM问题由于需要做外部传感器的触发同步,所以需要一个方波,考虑用Xavier的PWM,结果折腾了好久发现需要配置内部硬件,折
    发表于 01-10 08:11

    记录写SAM4S的bootloader所

    记录写SAM4S的bootloader所
    发表于 01-24 07:16

    关于RK1808板子调试过程过的记录

    关于RK1808板子调试过程过的记录
    发表于 02-16 06:38

    STM32H7+UCOSIII+LWIP记录相关资料推荐

    STM32H7+UCOSIII+LWIP记录主要功能:单片机作TCP服务器实现PC端多客户端连接单片机,并发传输数据。点1、优先级问题:一个客户端连接就创建一个线程,优先级由高到
    发表于 02-18 06:30

    嵌入式Linux记录

    Linux记录记录Linux学习过程过的与如何解决
    发表于 11-01 17:21 10次下载
    嵌入式Linux<b class='flag-5'>踩</b><b class='flag-5'>坑</b><b class='flag-5'>记录</b>

    STM32CubeIDE+FREERTOS记录

    STM32CubeIDE+FREERTOS记录
    发表于 12-05 18:06 15次下载
    STM32CubeIDE+FREERTOS<b class='flag-5'>踩</b><b class='flag-5'>坑</b><b class='flag-5'>记录</b>

    STM32H7+UCOSIII+LWIP记录

    STM32H7+UCOSIII+LWIP记录主要功能:单片机作TCP服务器实现PC端多客户端连接单片机,并发传输数据。点1、优先级问题:一个客户端连接就创建一个线程,优先级由高到
    发表于 12-23 19:54 5次下载
    STM32H7+UCOSIII+LWIP<b class='flag-5'>踩</b><b class='flag-5'>坑</b><b class='flag-5'>记录</b>

    推挽电路的,你过没?

    推挽电路的,你过没?
    的头像 发表于 11-24 16:25 1043次阅读
    推挽电路的<b class='flag-5'>坑</b>,你<b class='flag-5'>踩</b>过没?

    反相输入放大器的,你过没有?

    反相输入放大器的,你过没有?
    的头像 发表于 12-06 15:35 565次阅读
    反相输入放大器的<b class='flag-5'>坑</b>,你<b class='flag-5'>踩</b>过没有?