MySQL中ON DUPLICATE KEY UPDATE的介绍与使用、批量更新、存在即更新不存在则插入

文章目录

  • 一、ON DUPLICATE KEY UPDATE的介绍
  • 二、ON DUPLICATE KEY UPDATE的使用
    • 2.1、案例一:根据主键id进行更新
    • 2.2、案例二:根据唯一索引进行更新(常用)
    • 2.3、案例三:没有主键或唯一键字段值相同就插入
    • 2.4、案例四:主键与唯一键字段同时存在
  • 三、ON DUPLICATE KEY UPDATE的注意事项
    • 3.1、on dupdate key update之后values的使用事项
    • 3.2、对values使用判断
    • 3.3、唯一索引大小写敏感问题
  • 四、ON DUPLICATE KEY UPDATE与mybatis联合使用
    • 4.1、写法一:与values()联合使用
    • 4.2、写法二:使用#{}
  • 五、ON DUPLICATE KEY UPDATE的缺点及坑
    • 5.1、ON DUPLICATE KEY UPDATE每次更新导致id不连续
    • 5.2、death lock死锁

有时候由于业务需求,可能需要先去根据某一字段值查询数据库中是否有记录,有则更新,没有则插入。这个时候就可以用到ON DUPLICATE KEY UPDATE这个sql语句了。

以下内容基于本地windows环境mysql:8.0.34进行讲解。

一、ON DUPLICATE KEY UPDATE的介绍

基本用法:ON DUPLICATE KEY UPDATE​​是一种MySQL的语法,它在插入新数据时,如果遇到唯一键冲突(即已存在相同的唯一键值),则会执行更新操作,而不是抛出异常或忽略该条数据。这个语法可以大大简化我们的代码,减少不必要的判断和查询操作。

用法总结
1:on duplicate key update 语句根据主键id或唯一键来判断当前插入是否已存在。
2:记录已存在时,只会更新on duplicate key update之后指定的字段。
3:如果同时传递了主键和唯一键,以主键为判断存在依据,唯一键字段内容可以被修改。
4:唯一键大小写敏感时,大小写不同的值被认为是两个值,执行插入。参见下文中的大小写敏感问题

二、ON DUPLICATE KEY UPDATE的使用

准备表结构及测试数据, 注意:name是唯一键

drop table if exists tbl_test;
create table tbl_test(id int primary key auto_increment,name varchar(30) unique not null,age int comment '年龄',address varchar(50) comment '住址',update_time datetime default null
) comment '测试表';insert into tbl_test(name,age,address,update_time) values('zhangsan',20,'杭州',now()),('lisi',21,'武汉',now());

测试数据如下:
在这里插入图片描述

2.1、案例一:根据主键id进行更新

on dupdate key update 语句基本功能是:当表中没有原来记录时,就插入,有的话就更新。

如下sql:

insert into tbl_test(id,name,age,address,update_time) values(1,'zhangsan1',201,'杭州1','2024-03-05 15:59:35')
on duplicate key update
age = values(age), -- 注意:values()括号中的内容是字段名称。比如:在java程序中使用时表字段可能叫user_name, 实体类中是userName,values()里面要填user_name
address = values(address),
update_time=now();

在这里插入图片描述

从执行结果可以看出,更新了id为1的age,address两个字段,而name字段没有修改生效。由此我们可以得出两个重要结论:
1:on duplicate key update 语句根据主键id来判断当前插入是否已存在。
2:已存在时,只会更新on duplicate key update之后限定的字段。

2.2、案例二:根据唯一索引进行更新(常用)

根据唯一索引进行更新是生产中比较常用的方式,因为id一般使用的是自增,很少会先把id查询出来,然后根据id进行更新。

如下sql:

insert into tbl_test(name,age,address) values('zhangsan',202,'杭州2')
on duplicate key update
age = values(age), -- 注意:values()括号中的内容是字段名称。比如:在java程序中使用时表字段可能叫user_name, 实体类中是userName,values()里面要填user_name
address = values(address),
update_time=now();

在这里插入图片描述

从执行结果看,这次没有传id,但是age,address字段仍然更新了。
由此可以得出另一个结论:
3:on duplicate key update 语句也可以根据唯一键来判断当前插入的记录是否已存在。

2.3、案例三:没有主键或唯一键字段值相同就插入

如下sql:

insert into tbl_test(name,age,address) values('zhangsan3',203,'杭州3')
on duplicate key update
age = values(age), -- 注意:values()括号中的内容是字段名称。比如:在java程序中使用时表字段可能叫user_name, 实体类中是userName,values()里面要填user_name
address = values(address),
update_time=now();

在这里插入图片描述
这条执行就比较简单了,没有主键或唯一键字段值相同,即判断当前记录不存在,新插入一条。

注意: 这里我们发现主键id并没有连续,直接从2变成了4,具体原理可见《MySQL数据库设置主键自增、自增主键为什么不能保证连续递增》

2.4、案例四:主键与唯一键字段同时存在

如下sql:

insert into tbl_test(id,name,age,address) values(1,'zhangsan4',204,'杭州4')
on duplicate key update
name = values(name),
age = values(age), -- 注意:values()括号中的内容是字段名称。比如:在java程序中使用时表字段可能叫user_name, 实体类中是userName,values()里面要填user_name
address = values(address),
update_time=now();

在这里插入图片描述
从上面可以看出,连唯一键name也被修改了。结论:
4:如果传递了主键,是可以修改唯一键字段内容的。
这里要注意,如果这里的name修改为 lisi,zhangsan3
会报唯一键冲突的。可以自行尝试。

三、ON DUPLICATE KEY UPDATE的注意事项

3.1、on dupdate key update之后values的使用事项

如下sql:

insert into tbl_test(name,age,address,update_time) values('zhangsan4',205,'杭州5','2024-03-05 00:00:00')
on duplicate key update
age = age,
address = '杭州',
update_time=values(update_time);

在这里插入图片描述
on dupdate key update之后没有用values的情况
分为两种情况:
1:如果为如上面的address= “杭州”,则会一直更新为"杭州".
2:如果为如上面的age = age,则age会保持数据库中的值,不会更新。
3:只有当使用了values后,才会更新为上下文中传入的值

3.2、对values使用判断

如下sql

insert into tbl_test(id,name,age,address) values(1,'zhangsan',202,'杭州2')
on duplicate key update
name = ifnull(values(name),name),
age = values(age)

达到的效果是,如果传入的name值为null,则不更新。不为null则更新。这里与mybatis配合使用比较好。

3.3、唯一索引大小写敏感问题

思考这么一个问题:如上面name作为唯一索引,当name大小写敏感时且数据库中存储了name=“zhangsan” ,那么再插入name="ZHANGSAN"是更新还是新增?

1):唯一索引大小写不敏感时
设置name字段为唯一索引且大小写不敏感

drop table if exists tbl_test;
create table tbl_test(id int primary key auto_increment,name varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci unique not null,age int comment '年龄',address varchar(50) comment '住址',update_time datetime default null
) comment '测试表';insert into tbl_test(name,age,address,update_time) values('zhangsan',20,'杭州',now());
insert into tbl_test(name,age,address,update_time) values('ZHANGSAN',21,'杭州1',now());

在这里插入图片描述
可以看到当字段为大小写不敏感时zhangsan跟ZHANGSAN被认为是同一个值,不能重复插入。

当数据库中name=zhangsan时且name字段大小写不敏感时,我们看一下name="ZHANGSAN"能否更新成功?

insert into tbl_test(name,age,address,update_time) values('ZHANGSAN',22,'杭州2','2024-03-05 00:00:00')
on duplicate key update
age = values(age),
address = values(address),
update_time=values(update_time);

在这里插入图片描述
以上结果可以看出,当大小写不敏感时on duplicate key update是可以更新成功的,即认为是同一个值。

2):唯一索引大小写敏感时
设置name字段为唯一索引且大小写敏感

drop table if exists tbl_test;
create table tbl_test(id int primary key auto_increment,name varchar(30) CHARACTER SET utf8 COLLATE utf8_bin unique not null,age int comment '年龄',address varchar(50) comment '住址',update_time datetime default null
) comment '测试表';insert into tbl_test(name,age,address,update_time) values('zhangsan',20,'杭州',now());
insert into tbl_test(name,age,address,update_time) values('ZHANGSAN',21,'杭州1',now());

在这里插入图片描述
可以看到当字段为大小写敏感时zhangsan跟ZHANGSAN被认为是两个值,插入了两条记录。所以此时用on duplicate key update会执行新增操作

四、ON DUPLICATE KEY UPDATE与mybatis联合使用

4.1、写法一:与values()联合使用

注意:values后面的内容是表字段名称即带下划线,而不是实体类驼峰名称

如下sql: dept_id为主键或唯一索引

<insert id="replaceInto">INSERT INTO sys_dept(dept_id,parent_id,status,update_time) VALUES<foreach collection="deptList" item="item" separator=",">(#{item.deptId},#{item.parentId},#{item.status},#{item.updateTime})</foreach>ON DUPLICATE KEY UPDATEparent_id=VALUES(parent_id),status=VALUES(status),update_time=VALUES(update_time)
</insert>

4.2、写法二:使用#{}

如下sql: dept_id为主键或唯一索引

<insert id="replaceInto">INSERT INTO sys_dept(dept_id,parent_id,status,update_time) VALUES<foreach collection="deptList" item="item" separator=",">(#{item.deptId},#{item.parentId},#{item.status},#{item.updateTime})</foreach>ON DUPLICATE KEY UPDATE<foreach collection="deptList" item="item" separator=",">parent_id =  #{item.parentId},status = #{item.status},update_time = #{item.updateTime}</foreach>
</insert>

五、ON DUPLICATE KEY UPDATE的缺点及坑

5.1、ON DUPLICATE KEY UPDATE每次更新导致id不连续

如下sql:

drop table if exists tbl_test;
create table tbl_test(id int primary key auto_increment,name varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci unique not null,age int comment '年龄',address varchar(50) comment '住址',update_time datetime default null
) comment '测试表';insert into tbl_test(name,age,address,update_time) values('zhangsan',20,'杭州',now()),('李四',21,'武汉',now());

在这里插入图片描述
执行on duplicate key update进行更新,然后再插入一条新的数据

insert into tbl_test(name,age,address,update_time) values('zhangsan',22,'杭州2','2024-03-05 00:00:00')
on duplicate key update
age = values(age),
address = values(address),
update_time=values(update_time);insert into tbl_test(name,age,address,update_time) values('王五',23,'深圳',now());

在这里插入图片描述
可以看到id自增值从2直接变成了4,造成了id的不连续。

1.ON DUPLICATE KEY UPDATE每次更新导致id不连续原理:
mysql中有个配置值是innodb_autoinc_lock_mode。
innodb_autoinc_lock_mode中有3中模式,0,1和2,mysql5的默认配置是1,

  • 0是每次分配自增id的时候都会锁表.
  • 1只有在bulk insert的时候才会锁表,简单insert的时候只会使用一个light-weight mutex,比0的并发性能高
  • 2.没有仔细看,好像是很多的不保证…不太安全.

数据库默认是1的情况下,就会发生上面的那种现象,每次使用insert into … on duplicate key update 的时候都会把简单自增id增加,不管是发生了insert还是update

5.2、death lock死锁

经常看到网上说ON DUPLICATE KEY UPDATE会导致死锁,确实是存在这个可能的,不过由于目前没有特别好的方案,所以也只能使用这个sql语法了。在执行insert ... on duplicate key语句时,如果不对同一个表同时进行并发的insert或者update,基本不会造成死锁。即insert ... on duplicate key时尽量单线程串行进行新增或更新

insert … on duplicate key 在执行时,innodb引擎会先判断插入的行是否产生重复key错误,如果存在,在对该现有的行加上S(共享锁)锁,如果返回该行数据给mysql,然后mysql执行完duplicate后的update操作,然后对该记录加上X(排他锁),最后进行update写入。

如果有两个事务并发的执行同样的语句,那么就会产生death lock,如:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/541107.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端和后端权限控制【笔记】

前端权限设置【笔记】 前言版权推荐前端权限设置需求效果实现资源 后端权限控制1.给所有前端请求都携带token2.添加拦截器3.配置到WebMvcConfiguration4.更多的权限验证 最后 前言 2024-3-15 18:27:26 以下内容源自《【笔记】》 仅供学习交流使用 版权 禁止其他平台发布时删…

点的基本操作

点的基本操作 要求 提供空间点数据文本文件&#xff0c;包含ID、name、X、Y四个字段信息&#xff0c; 1&#xff09;读取数据&#xff0c;并且在窗口中显示点的具体位置&#xff0c;用实心圆绘制。 2&#xff09;鼠标任意点击三个点&#xff0c;将点连线&#xff0c;用黑色笔…

误分区酿苦果,数据恢复有妙方

一、误操作引发分区混乱 在数字化时代的浪潮中&#xff0c;硬盘分区成为我们管理和存储数据的重要手段。然而&#xff0c;误分区这一操作失误&#xff0c;却时常给许多用户带来不小的困扰。误分区&#xff0c;简单来说&#xff0c;就是在对硬盘进行分区操作时&#xff0c;由于…

[云原生] Prometheus之部署 Alertmanager 发送告警

一、Alertmanager 发送告警的介绍 Prometheus 对指标的收集、存储与告警能力分属于 Prometheus Server 和 AlertManager 两个独立的组件&#xff0c;前者仅负责定义告警规则生成告警通知&#xff0c; 具体的告警操作则由后者完成。 Alertmanager 负责处理由 Prometheus Serve…

807补充(十一)(鞍论与随机逼近理论篇)

807补充&#xff08;十一&#xff09;&#xff08;鞍论与随机逼近理论篇&#xff09; 一.高等概率论初步 Theorem: σ − \sigma- σ− 代数,如果样本空间 Ω \Omega Ω 的一系列子集的集合 F \mathcal{F} F 满足: (1) ∅ ∈ F \emptyset \in \mathcal{F} ∅∈F (2) 若 A …

AVCE - AV Evasion Craft Online 更新 8 种加载方式 - 过 WD 等

免责声明&#xff1a;本工具仅供安全研究和教学目的使用&#xff0c;用户须自行承担因使用该工具而引起的一切法律及相关责任。作者概不对任何法律责任承担责任&#xff0c;且保留随时中止、修改或终止本工具的权利。使用者应当遵循当地法律法规&#xff0c;并理解并同意本声明…

LeetCode 热题 100 | 回溯(二)

目录 1 39. 组合总和 2 22. 括号生成 3 79. 单词搜索 菜鸟做题&#xff0c;语言是 C&#xff0c;感冒快好版 关于对回溯算法的理解请参照我的上一篇博客&#xff1b; 在之后的博客中&#xff0c;我将只分析回溯算法中的 for 循环。 1 39. 组合总和 题眼&#xff1a;c…

网站被挂马劫持的解决办法

首先&#xff0c;应该检查网站的DNS记录&#xff0c;以确定是否有人修改了DNS记录。如果发现有人修改了DNS记录&#xff0c;应该立即更改DNS记录&#xff0c;以恢复网站的正常访问。此外&#xff0c;应该检查网站的源代码&#xff0c;以确定是否有人植入了恶意代码。如果发现有…

【Web】浅聊Java反序列化之玩转Hessian反序列化的前置知识

目录 序列化 反序列化 Hessian1.0 Hessian2.0 Hessian反序列化核心&#xff1a;MapDeserializer#readMap的利用 总结 序列化 HessianOutput&Hessian2Output都是抽象类AbstractHessianOutput的实现类 HessianOutput#writeObject和Hessian2Output#writeObject的写法是…

Rocketmq专题-01 v5版单机部署篇

Rocketmq专题 注&#xff1a; 本教程由羞涩梦整理同步发布&#xff0c;本人技术分享站点&#xff1a;blog.hukanfa.com 转发本文请备注原文链接&#xff0c;本文内容整理日期&#xff1a;2024-01-28 csdn 博客名称&#xff1a;五维空间-影子&#xff0c;欢迎关注 说明 地址…

通过spring boot/redis/aspect 防止表单重复提交【防抖】

一、啥是防抖 所谓防抖&#xff0c;一是防用户手抖&#xff0c;二是防网络抖动。在Web系统中&#xff0c;表单提交是一个非常常见的功能&#xff0c;如果不加控制&#xff0c;容易因为用户的误操作或网络延迟导致同一请求被发送多次&#xff0c;进而生成重复的数据记录。要针…

分布式思想

1、单体架构设计存在的问题 传统项目采用单体架构设计,虽然可以在一定的程度上解决企业问题,但是如果功能模块众多,并且将来需要二次开发.由于模块都是部署到同一台tomcat服务器中,如果其中某个模块代码出现了问题,将直接影响整个tomcat服务器运行. 这样的设计耦合性太高.不便…