Mybatis-Plus使用saveOrUpdate及问题解决方法

今天的想法是,要在插入数据库时,如果有某某一个主要字段的值重复,则不插入,否则则插入!
看了一下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
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;

}

不过还有个问题,就是这个是根据主键做操作的,但是我主键本来就是自动递增肯定不会有问题的,接下来就是想个办法,让他根据指定字段做操作,好像是有提供了一个口子。

// 根据updateWrapper尝试更新,否继续执行saveOrUpdate(T)方法
boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper);

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

研究尝试了半天,终于搞出来了,可能是很少有人会像我这样做吧!所以我自己尝试了下。

当saveOrUpdate不使用条件构造器时,会先做根据主键查询,如果查出来的结果为0,那么就执行插入操作,如果查出来的结果不为0,则执行更新操作。

但是一般情况下,主键都不会重复啊!所有我就用条件构造器Wrapper!

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

这样改变后的结果就是会先执行修改,如果执行一条,则执行成功,如果执行结果为0,再执行根据主键查询,然后做插入操作!

其实有点多此一举的感觉,因为既然都已经更新不到结果了,那么肯定是没有这个字段咯!

不过转念一想,你是指定字段没有,又不是主键没有!

但是主键自增那肯定没有啊!

所有我又想到一个骚操作,我不传UpdateWrapper而传QueryWrapper会怎么样呢!

会不会加在查询条件种呢!我丢进去没有报错,有点小激动,不知道结果如何!

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

好吧!上来全给我Update了!丝毫不留情面!我把数据删了再试试!

好吧!然并卵!幻想破灭!跟传UpdateWrapper没有区别!~告辞!

看了一下源码,默认参数是Wrapper类型,然后根据条件构造器更新,

成功则返回,

不成功则走无条件构造器的方法。

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

我感觉应该加个类型判断!

if(updateWrapper instanceof QueryWrapper){
 	去拼接查询语句!
 }
  if(updateWrapper instanceof UpdateWrapper){
 	去拼接更新语句!
 }

这样就不会只根据ID来死查了!

2021-05-21 11:07:24

我才终于明白~

为什么要用updateWrapper了!

它与queryWrapper的区别就是。

updateWrapper用set来设置修改的数据。

queryWrapper应用select来设置要查出来的数据。

哈哈,这个还是很重要的!

saveOrUpdate 是否有映射id

我们知道mybatis在插入时,会映射id,但是如果是saveOrUpdate会怎么样呢?

比如我saveOrUpdate()后,需要用他的id,但是我传进去的对象是没有id的。

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

可以看到他先通过id查了没有再进行插入,然后返回新的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

不过这个update,不用试我都感觉难搞,因为你如果没有id,那么你传入这个对象的值,可能查出多个对象,那么他要把哪个id映射回来,是吧!

@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());
 }

但还是试一下,当我们加了一个UpdateWrapper后,有执行成功,执行了3条,返回了id为0。

但是这次加了wrapper,我再试试如果只插入一条,会怎么样。哈哈,不去读源码去debug,就只能这样试试了,莫怪。

诶,对啊,我去看看源码先,看能不能看出什么门道。

之前好像也有看了点源码。两种不同构造的方法,执行的逻辑也不一样。

boolean saveOrUpdate(T entity);	

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

区别不大,就是会多执行一步更新,如果执行成功就直接走,执行不成功再根据这个对象做saveOrUpdate。

进去翻了翻就是,如果通过id查到值,就根据id更新,不然就做新增。

所以也就不用试了,还是自己手写一个吧,如果需要返回id的话。

慎用!

细思极恐,当你是主键自动生成的数据,一定要写UpdateWrapper,不然你必然是一直插入!完全不会更新,因为默认是用id查询的。

而主键生成的数据,一般都不会去写一个id,所以啊!赶快看看吧!

UpdateWrapper 小贴士

上面虽然写了updateWrapper可以写一个set属性,有两种情况。

首先,我们一个对象,有5条属性,只有4条有值,1条没有值。

mybatis-plus在执行时,会先去看看你的对象哪条属性有值,哪条没有。

只会更新有值的属性,所以只会更新4个属性,另外一个属性并不会把他置空。

如果你只想改一条属性,也可以多写一个set,不过感觉没啥必要,不过比较灵活的就是。
你想写另外一个值,就可以写进set里。

2021-05-21 13:31:32

我发现一个很垃圾的,前面我吹的那个updateWrapper的set多牛逼,其实是我想的太美了,他只是在原本的基础上再加一个字段!我吐了!

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

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

两个score,我吐了!

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

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

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

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

到此这篇关于Mybatis-Plus使用saveOrUpdate及问题解决方法的文章就介绍到这了,更多相关Mybatis-Plus saveOrUpdate内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • mybatis-plus 关于savebatch,saveorupdatebatch遇到的坑及解决办法

    目录 一.背景 二.解决办法 三.sql注入器实现批量更新,批量新增或更新功能 一.背景 最近mybatis-plus框架的更新,让我们基础开发中如虎添翼.其中基本的增删改查,代码生成器想必大家用着那叫一个爽.本人在使用中,也遇到一些坑.比如savebatch,saveorupdatebatch,看着这不是批量新增,批量新增或更新嘛,看着api进行开发,感觉也太好用啦.开发完一测试,速度跟蜗牛一样,针对大数据量真是无法忍受.在控制台上发现,怎么名义上是批量插入,还是一条一条的进行插入,难怪速度龟

  • mybatis如何实现saveOrUpdate

    目录 1. selectKey标签查询 2. 主键自增或者累加的,不使用selectKey 3. 主键为varchar的使用ON DUPLICATE KEY UPDATE 总结 1. selectKey标签查询 DDL CREATE TABLE `luck_reward_info` (   `id` int NOT NULL AUTO_INCREMENT COMMENT 'id',   `activity_id` varchar(20) CHARACTER SET utf8mb4 COLLATE

  • Mybatis-Plus使用saveOrUpdate及问题解决方法

    今天的想法是,要在插入数据库时,如果有某某一个主要字段的值重复,则不插入,否则则插入!看了一下mybatis-Plus是有这个saveOrUpdate 方法! 原本使用save时是没有问题了,改成saveOrUpdate 用了一下就报错了. com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: error: can not execute. because can not find column for id from en

  • mybatis连接MySQL8出现的问题解决方法

    使用MySQL8,在整合ssm框架,用mybatis逆向工程生成的代码测试时,执行到数据库查询前均正常,但进行查询时,便卡主没有反应了,设置了日志.try catch等也不报错,页面就在那一直转,之前mybatis自动生成代码都是正常的,然后在测试类中,使用Connection进行连接测试并查询数据库,也是能够正常查询到数据的: Connection conn = null; try { String userName = "root"; String password = "

  • Mybatis-plus与Mybatis依赖冲突问题解决方法

    错误描述 An attempt was made to call a method that does not exist. The attempt was made from the following location: com.baomidou.mybatisplus.core.MybatisMapperAnnotationBuilder.getLanguageDriver(MybatisMapperAnnotationBuilder.java:369) The following met

  • vue.js element-ui validate中代码不执行问题解决方法

    先说结论 在自定义验证里面每一个判断都要有callback(),就是要保证callback()一定会执行到 因为要验证数字,参考了官网参考代码如下,发现有如下图bug,当输入为以数字开头包含字符串的内容时,验证不会报错,因为业务逻辑也不相符,随改写代码 <el-form-item label="年龄" prop="age"> <el-input v-model.number="ruleForm2.age"></el-

  • java 多线程饥饿现象的问题解决方法

    java 多线程饥饿现象的问题解决方法 当有线程正在读的时候,不允许写 线程写,但是允许其他的读线程进行读.有写线程正在写的时候,其他的线程不应该读写.为了防止写线程出现饥饿现象,当线程正在读,如果写线程请求写,那么应该禁止再来的读线程进行读. 实现代码如下: File.Java package readerWriter; public class File { private String name; public File(String name) { this.name=name; } }

  • python中requests爬去网页内容出现乱码问题解决方法介绍

    最近在学习python爬虫,使用requests的时候遇到了不少的问题,比如说在requests中如何使用cookies进行登录验证,这可以查看这篇文章.这篇博客要解决的问题是如何避免在使用requests的时候出现乱码. import requests res=requests.get("https://www.baidu.com") print res.content 以上就是使用requests进行简单的网页请求数据的方式.但是很容易出现乱码的问题. 我们可以通过在网页上右击查看

  • Ubuntu“无法打开锁文件(Could not get lock)”问题解决方法

    用apt-get安装软件时提示: 无法获得锁 /var/lib/dpkg/lock - open(11:资源暂时不可用) 无法锁定管理目录(/var/lib/dpkg/),是否有其他进程正占用它? 其实报错已经给了提示了,就是有进程正在占用apt-get命令,So... 命令跑起来,找出这个进程,kill这个进程! ps -aux | grep "apt" sudo kill PID(进程编号) 检查是否还有apt进程: ps -e | grep apt 如果没有提示,则表示apt进程

  • Android编程开发ScrollView中ViewPager无法正常滑动问题解决方法

    本文实例讲述了Android编程开发ScrollView中ViewPager无法正常滑动问题解决方法.分享给大家供大家参考,具体如下: 这里主要介绍如何解决ViewPager在ScrollView中滑动经常失效.无法正常滑动问题. 解决方法只需要在接近水平滚动时ScrollView不处理事件而交由其子View(即这里的ViewPager)处理即可,重写ScrollView的onInterceptTouchEvent函数,如下: package cc.newnews.view; import an

  • Mybatis调用视图和存储过程的方法

    现在的项目是以Mybatis作为O/R映射框架,确实好用,也非常方便项目的开发.MyBatis支持普通sql的查询.视图的查询.存储过程调用,是一种非常优秀的持久层框架.它可利用简单的XML或注解用语配置和原始映射,将接口和java中的POJO映射成数据库中的纪录. 一.调用视图 如下就是调用视图来查询收益明细,sql部分如下: <!-- 获取明细 --> <select id ="getContactEarnsDetail" resultType= "ja

  • CloudStack SSVM启动条件源码阅读与问题解决方法

    CloudStack SSVM启动条件源码阅读与问题解决方法: 在CloudStack建立zone的时候,经常遇到SSVM不启动,或者根本就没有SSVM的情况,分析CloudStack日志,会发现有"Zone 1 is not ready to launch secondary storage VM yet"打印,意思是zone还未准备好启动SSVM. 通过查询CloudStack源代码,发现启动SSVM前有如下检查:         获取Zone里的template. select

随机推荐