MySQL优化--INSERT ON DUPLICATE UPDATE死锁
INSERT ON DUPLICATE UPDATE与死锁
在MySQL中提供两种插入更新的方式:REPLACE INTO和INSERT ON DUPLICATE UPDATE,简化了“存在则更新,不存在则插入”的实现逻辑,但这两种方式在MySQL内部都被拆分为多个操作步骤且引入GAP锁来保证数据完整性,因此在高并发情况下极易产生死锁。
##==================================================##
在MySQL中INSERT ON DUPLICATE UPDATE的加锁流程:
1. Innodb存储引擎尝试INSER INTO操作
2. 如果插入成功,则忽略DUPLICATE UPDATE部分并返回
3. 如果插入失败,则表明有相同记录存在,对该记录加共享锁(S)
4. 执行DUPLICATE UPDATE语句,对记录加X锁,然后更新记录。
##==================================================##
对于INSERT ON DUPLICATE UPDATE操作,当两个会话S1和S2使用INSERT ON DUPLICATE UPDATE语句操作相同数据且表中存在相同键值记录时,触发死锁场景为:
1. 由于表中已存在重复键值的记录,导致会话先后尝试INSER失败
2. 会话S1进入步骤3尝试获取记录的S锁,该记录未被其他会话加锁,获取S锁成功。
3. 会话S2进入步骤3尝试获取记录的S锁,该记录上被加持S锁,但由于S锁与S锁兼容,获取S锁成功
4. 会话S1进入步骤4尝试获取记录的X锁,由于会话S2对该记录持有S锁,S锁与X锁不兼容,获取X锁失败,会话S1被阻塞
5. 会话S2进入步骤4尝试获取记录的X锁,由于会话S1对该记录持有S锁,S锁与X锁不兼容,获取X锁失败,会话S2被阻塞
6. 会话S2被阻塞后进入死锁检查环节,发现阻塞S1->S2和S2->S1形成死锁环路,触发死锁机制强制回滚S1或S2事务。
##==================================================##
在MySQL默认隔离级别REPEATABLE READ下,为避免出现"幻读"发生,防止其他会话插入相同键值的记录。
对于普通INSERT操作加锁如下:
1. 对于非唯一索引,需要对新记录加排他锁(X),另外对新记录和新记录的相邻记录的区间加gap锁。
2. 对于唯一索引,仅需要对新记录加排他锁(X),唯一索引特性保证其他会话无法插入相同键值。
对于INSERT ON DUPLICATE UPDATE操作,当表中未存在重复键值记录时,加锁特点如下:
1. 对于唯一索引和非唯一索引,都需要对新记录加排他锁(X),另外对新记录和新记录的相邻记录的区间加gap锁。
##==================================================##
准备测试数据:
CREATE TABLE `tb2002` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`c1` varchar(20) DEFAULT NULL,
`c2` varchar(20) DEFAULT NULL,
`c3` int(11) DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_c1` (`c1`,`c2`)
) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8;
insert into tb2002(c1,c2) values('a','1');
insert into tb2002(c1,c2) values('f','1');
开始测试:
会话1执行:
insert into tb2002(c1,c2) values('d','2') ON DUPLICATE KEY UPDATE c3=c3+1;
执行成功
会话2执行:
insert into tb2002(c1,c2) values('c','1') ON DUPLICATE KEY UPDATE c3=c3+1;
执行被阻塞,等待X+GAP锁,GAP锁的行记录目标是('f','1')
会话1执行:
insert into tb2002(c1,c2) values('d','1') ON DUPLICATE KEY UPDATE c3=c3+1;
触发死锁,会话2被回滚,会话1执行成功
##==================================================##
通过上面两个死锁案例,我们强烈建议在生产环境中尽量避免使用REPLACE INTO和INSERT INTO ON DUPLICATE UPDATE语句,改用普通INSERT操作,并对INSER操作部分代码加入异常加查,当INSERT失败时改为UPDATE操作。
MySQL优化--INSERT ON DUPLICATE UPDATE死锁的更多相关文章
- Mysql中INSERT ... ON DUPLICATE KEY UPDATE的实践
转: Mysql中INSERT ... ON DUPLICATE KEY UPDATE的实践 阿里加多 0.1 2018.03.23 17:19* 字数 492 阅读 2613评论 2喜欢 1 一.前 ...
- sqlalchemy insert on duplicate update
sqlalchemy insert on duplicate update from sqlalchemy.dialects.mysql import insert insert_stmt = ins ...
- MySQL的INSERT ··· ON DUPLICATE KEY UPDATE使用的几种情况
在MySQL数据库中,如果在insert语句后面带上ON DUPLICATE KEY UPDATE 子句,而要插入的行与表中现有记录的惟一索引或主键中产生重复值,那么就会发生旧行的更新:如果插入的行数 ...
- SQLSERVER 中实现类似Mysql的 INSERT ON DUPLICATE KEY UPDATE
通过SQLServer创建索引时,有一个IGNORE_DUP_KEY的选项,可以类似实现. IGNORE_DUP_KEY = { ON | OFF } 指定对唯一聚集索引或唯一非聚集索引执行多行插入操 ...
- 死锁问题------------------------INSERT ... ON DUPLICATE KEY UPDATE*(转)
前言 我们在实际业务场景中,经常会有一个这样的需求,插入某条记录,如果已经存在了则更新它如果更新日期或者某些列上的累加操作等,我们肯定会想到使用INSERT ... ON DUPLICATE K ...
- INSERT ... ON DUPLICATE KEY UPDATE产生death lock死锁原理
前言 编辑 我们在实际业务场景中,经常会有一个这样的需求,插入某条记录,如果已经存在了则更新它如果更新日期或者某些列上的累加操作等,我们肯定会想到使用INSERT ... ON DUPLICATE K ...
- Mysql死锁如何排查:insert on duplicate死锁一次排查分析过程
前言 遇到Mysql死锁问题,我们应该怎么排查分析呢?之前线上出现一个insert on duplicate死锁问题,本文将基于这个死锁问题,分享排查分析过程,希望对大家有帮助. 死锁案发还原 表结构 ...
- mysql优化 ON DUPLICATE KEY UPDATE
场景:比如,有一张表,专门记录业务里的唯一数据记录,这张表里如果存在此唯一数据的记录就更新此行数据的某个字段,如果此唯一数据不存在,那么就添加一条最新数据. 一贯操作:如果不知道mysql有 ON D ...
- mysql 插入重复值 INSERT ... ON DUPLICATE KEY UPDATE
向数据库插入记录时,有时会有这种需求,当符合某种条件的数据存在时,去修改它,不存在时,则新增,也就是saveOrUpdate操作.这种控制可以放在业务层,也可以放在数据库层,大多数数据库都支持这种需求 ...
随机推荐
- pm2管理node
一般直接npm start起的退出命令行就没了,node后台管理工具pm2目前比较流行. npm install -g pm2 pm2 list pm2 start bin/www --name de ...
- Android面试准备20190422
1.即时推送原理,采用的push推送模式,保持一个长连接,服务端和客户端连接后不再断开.所谓长连接,即是在一个TCP上可以连续发送多个数据包,在TCP连接保持期间,如果没有数据包发送,需要双方发送检测 ...
- Vue仿string.format
Vue.prototype.$stringFormat = function stringFormat (formatted, args) { for (let i = 0; i < args. ...
- Memcached和Memcache安装(64位win7)[z]
http://www.cnblogs.com/lucky-man/p/6126667.html 一.Memcached和Memcache的区别: 网上关于Memcached和Memcache的区别的理 ...
- winform自定义控件中其他遮挡控件点击事件
自定义控件在其他窗口调用时,里面的lable阻挡了控件的点击事件 解决方法 自定义控件中lable的 点击事件 private void Lable1_Click(object sender, Eve ...
- mysql 索引及索引创建原则
是什么 索引用于快速的查询某些特殊列的某些行.如果没有索引, MySQL 必须从第一行开始,然后通过搜索整个表来查询有关的行.表越大,查询的成本越大.如果表有了索引的话,那么 MySQL 可以很快的确 ...
- linux学习第十八天 (Linux就该这么学)
今天讲了23章节,OPENLDAP安装配置,感觉好难 ,不过考试测试,CA也没有了,主要还讲了数据库mariadb,安装,配置,使用,基本的数据库管理,还讲了,网络安装系统,我暂时先不写其它了,上传图 ...
- springboot无法加载oracle驱动终极解决
.ctrl+shirt+s .找到 Maven: com.oracle:ojdbc6: .找到classes 下的路径C:\Users\Administrator\.m2\repository\com ...
- vue项目部署到服务器
1.配置config目录下index.js index: path.resolve(__dirname, '../dist/index.html'), assetsRoot: path.resolve ...
- zabbix监控配置与邮件告警
添加主机与主机组 进入web页面,在 配置-主机群组,创建主机群组 在 配置-主机,新建主机 在可见的名称中建议填写为类似 主机类型-主机名-IP或域名 的格式,如Web-Hyrule001-192. ...