MySQL的INSERT ... FOR UPDATE你用过吗

举报
沙师弟 发表于 2023/12/03 17:24:14 2023/12/03
【摘要】 引言了不起最近处理了一个生产问题,具体情况是这样的:就是两个sql语句在同一个代码块中,第一个sql语句是对设备状态根据设备ID批量删除,第二个sql语句是批量插入,插入的设备ID和删除的设备ID是同一个。本地和测试环境当时都好好的,可是上了生产环境,报错了错误是存在重复的唯一索引,代码逻辑很简单可以看到就是一个批量删除,再批量插入,测试环境当时没有用多个实例进行测试,上产是有多个实例的,错...

引言

了不起最近处理了一个生产问题,具体情况是这样的:

就是两个sql语句在同一个代码块中,第一个sql语句是对设备状态根据设备ID批量删除,第二个sql语句是批量插入,插入的设备ID和删除的设备ID是同一个。

本地和测试环境当时都好好的,可是上了生产环境,报错了

image.png

错误是存在重复的唯一索引,代码逻辑很简单

image.png

可以看到就是一个批量删除,再批量插入,测试环境当时没有用多个实例进行测试,上产是有多个实例的,错误的发生情况当天下班后一直分析到晚上12点,终于分析出来了,如下图:

image.png

可以看到是同时来了两个请求,分别落到了2台机器,这段代码在2个机器上执行就不能保证顺序性了,这个要加锁的话也是分布式锁。

不过还可以通过数据库的行锁来实现,接下来我们就一起来看看INSERT ... FOR UPDATE语句。

MySQL的 INSERT ... FOR UPDATE语句可以用于在插入新行的同时对这些行进行加锁,从而防止其他事务对这些行进行修改。下面简要介绍 INSERT ... FOR UPDATE语句的原理和应用场景,并举例说明其具体用法。

一、INSERT ... FOR UPDATE语句的原理

INSERT ... FOR UPDATE语句会在执行插入操作时,对插入的新行进行排他锁(Exclusive Lock)的加锁操作,从而避免其他事务对这些新行进行修改。

这种锁定机制同样是基于MySQL的事务隔离级别实现的,只有在可重复读(REPEATABLE READ)和串行化(SERIALIZABLE)隔离级别下,INSERT ... FOR UPDATE语句才能生效。

二、INSERT ... FOR UPDATE语句的应用场景

  1. 防止重复插入

在某些业务场景下,可能需要对某些数据进行唯一性约束,避免重复插入相同的数据。使用 INSERT ... FOR UPDATE语句可以避免并发的情况下,多个事务同时插入相同的数据。

  1. 实现悲观锁

在某些业务场景下,需要对某些数据进行严格的控制,确保数据不会被其他事务修改。使用 INSERT ... FOR UPDATE语句可以实现悲观锁,确保数据的安全性。

  1. 实现乐观锁

使用 INSERT ... FOR UPDATE语句可以实现乐观锁机制,即在插入数据的同时,记录数据的版本号或时间戳等信息,如果在插入时发现版本号或时间戳已经存在,则说明其他事务已经插入了相同的数据,需要进行相应的处理。

三、INSERT ... FOR UPDATE语句的应用举例

下面举例说明 INSERT ... FOR UPDATE语句的具体用法。

假设有一个用户表user,其中包含用户ID和用户名两个字段,现在需要往用户表中插入新用户,假设插入流程如下:

  1. 根据用户ID查询用户是否已经存在
  2. 如果用户不存在,则插入新用户

在这个过程中,需要对用户ID进行唯一性约束,避免重复插入相同的用户。

可以使用如下的SQL语句来实现插入操作:

START TRANSACTION;
SELECT * FROM user WHERE user_id = '123' FOR UPDATE;
INSERT INTO user(user_id, username) VALUES ('123', 'John');
COMMIT;

在这个SQL语句中,SELECT ... FOR UPDATE语句用于对选定的行进行加锁,防止其他事务对这些行进行修改,从而避免重复插入相同的用户。如果查询结果为空,则可以插入。

四、生产问题的解决

了不起这边处理的方式就很简单了,直接将批量插入sql的语句末尾加上了 FOR UPDATE。
语法参考:

insert into tablename values() on duplicate key update columnName = valueName;

由于具体涉及公司隐私就不贴sql语句了,原理就是当执行插入的时候,如果已经有这条数据存在,那么就更新它,就不会存在说已经插入了的数据在插入一条会报重复Key这个情况。

简单的INSERT ... FOR UPDATE你掌握了吧,后面我们继续学习。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。