mysql并发插入死锁_MySQL: 并发replace into的死锁问题分析-阿里云开发者社区
测试版本:MySQL5.6.23测试表:
create table t1 (a int auto_increment primary key, b int, c int, unique key (b));并发执行SQL:
replace into t1(b,c) values (2,3) //使用脚本,超过3个会话
背景
replace 操作可以算是比较常用的操作类型之一,我们先来理一下,对于上例,一条简单的replace into操作的主要流程包括哪些。
Step 1. 正常的插入逻辑
首先插入聚集索引,在上例中a列为自增列,由于未显式指定,每次Insert前都会生成一个不冲突的新值
随后插入二级索引b,由于其是唯一索引,在检查duplicate key时,加上记录锁,类型为LOCK_X (对于普通的INSERT操作,当需要检查duplicate key时,加LOCK_S锁,而对于Replace into 或者 INSERT..ON DUPLICATE操作,则加LOCK_X记录锁) 。 由于uk记录已存在,返回错误DB_DUPLICATE_KEY。
Step 2. 处理错误
由于检测到duplicate key,因此第一步插入的聚集索引记录需要被回滚掉(row_undo_ins)
Step 3. 转换操作
从InnoDB层失败返回到Server层后,收到duplicate key错误,首先检索唯一键冲突的索引,并对冲突的索引记录(及聚集索引记录)加锁
随后确认转换模式以解决冲突:
#如果发生uk冲突的索引是最后一个唯一索引、没有外键引用、且不存在delete trigger时,使用UPDATE ROW的方式来解决冲突
#否则,使用DELETE ROW + INSERT ROW的方式解决冲突
Step 4. 更新记录
在该例中,对聚集索引和二级索引的更新,都是采用标记删除+插入新记录的方式
对于聚集索引,由于PK列发生变化,采用delete + insert 聚集索引记录的方式更新
对于二级uk索引,同样采用标记删除 + 插入的方式
我们知道,在尝试插入一条记录时,如果插入位置的下一条记录上存在记录锁,那么在插入时,当前session需要对其加插入意向锁,具体类型为LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION
是否能保证自增列的有序性:
默认情况下,参数innodb_autoinc_lock_mode的值为1,因此只在分配自增列时互斥(如果我们将其设为0的话,就会产生AUTO_INC类型的表级锁)
当分配完自增列值后,我们并不知道并发的replace into的顺序。
死锁分析:
回到死锁线程分析,从死锁日志我们大致可以推断出如下序列:
Session 1 执行到Step4, 准备更新二级Uk索引,因此持有uk上heap no 为5的X 行锁和PK上的X行锁
Session 2 检查到uk冲突,需要加X行锁
Session 1 在标记删除记录后,尝试插入新的uk记录,发现预插入点的下一条记录(heap no =5) 上有锁请求,因此尝试加插入意向X锁,产生锁升级, 死锁路径:Session1 => Session 2 => Session1到这里,其实问题已经很明显了。 我们考虑如下场景:假设当前表内数据为:
root@sb1 08:57:41>select * from t1;
+———+——+——+
| a | b | c |
+———+——+——+
| 2100612 | 2 | 3 |
+———+——+——+
1 row in set (0.00 sec)
由于不能保证自增列被更新的有序性,我们假定session 1获得自增列值为2100619, session 2 获得的自增列值为2100614, session 3获得的自增列值为2100616
为了便于阐述,我们假定表上总是只有一条记录
Session 1:
replace into t1 values (2100619, 2, 3); // uk索引上记录(2, 2100612)被标记删除,同时插入新记录(2, 2100619)Purge线程启动,(2, 2100612)被物理删除,Page上只剩下唯一的物理记录(2, 2100619)
Session 2:
replace into t1 values (2100614, 2, 3);
这里我们使用gdb的non-stop模式,使其断在row_update_for_mysql函数(insert尝试失败后,会转换成update),此时session2持有(2, 2100619) 的X锁Tips:我们可以通过如下命令使用gdb的non-stop模式:
1. 以gdb启动mysqld
2. 设置:
set target-async 1
set pagination off
set non-stop on
3. 设置函数断点
Session 3:
replace into t1 values (2100616, 2, 3); // 检测到uk有冲突键,需要获取记录(2, 2100619) 的X锁,等待session 2
Session 2:
a)标记删除记录(2, 2100619),同时插入新记录(2, 2100614);
b) (2, 2100614) 比(2, 2100619) 要小,因此定位到该记录之前,也就是系统记录infimum
c)infimum记录的下一条记录(2, 2100619)上有锁等待,需要升级成插入意向X锁,导致死锁发生
假定Purge线程停止,会发生什么呢 ?
我们随便建一个表,然后执行FLUSH TABLE tbname FOR EXPORT来让purge线程停止,执行序列如下:root@sb1 10:26:05>select * from t1;
+———+——+——+
| a | b | c |
+———+——+——+
| 2100710 | 2 | 3 |
+———+——+——+
1 row in set (0.00 sec)session 1
session 1:
replace into t1 values (2100720, 2, 3);
此时Page上存在记录(infimum), (2, 2100710), (2, 2100720), (supremum)
session 2
replace into t1 values (2100715, 2, 3);
同上例,使用gdb断到函数row_update_for_mysql由于没有启动purge线程,因此老的被标记删除的记录还存在于page内,在扫描二级索引重复键时,也会依次给这些老记录加锁,因此session 2会持有 (2, 2100710)和 (2, 2100720)的X锁
session 3
replace into t1 values (2100718, 2, 3); // 被session2阻塞,等待(2,2100710)的X锁lock_mode:3, heap no:810
session 2
在标记删除二级索引记录,并进行插入时,选择的插入位置为 (2, 2100710), (2,2100720)之间,插入点的下一条记录(2,2100720)上没有其他线程锁等待,当前session锁升级成功
完成插入后,page上的记录分布为(infimum), (2, 2100710), (2, 2100715), (2, 2100720), (supremum)
session 3
完成插入,最终page内的记录为(infimum), (2, 2100710), (2, 2100715), (2, 2100718), (2, 2100720), (supremum)
其中只有用户记录(2, 2100718)未被标记删除
mysql并发插入死锁_MySQL: 并发replace into的死锁问题分析-阿里云开发者社区相关推荐
- 线上阿里云mysql慢_MySQL · 案例分析 · RDS MySQL线上实例insert慢常见原因分析-阿里云开发者社区...
概述 insert慢是经常被问到的问题,笔者尝试在本文中对这个问题做一个分类梳理,列举的线上例子会做简化,希望对读者有所启发. 注意:因为阿里云MySQL线上实例还是以RDS 5.6为主体,本文的分析 ...
- 阿里云 mysql日志分析_mysql 慢日志分析-阿里云开发者社区
启用 slow log 有两种启用方式: 1, 在my.cnf 里 通过 log-slow-queries[=file_name] 2, 在mysqld进程启动时,指定--log-slow-queri ...
- mysql 轨迹数据存储_基于Tablestore实现海量运动轨迹数据存储-阿里云开发者社区...
前言 现在越来越多的人都开始关心自己的运动数据,比如每日的计步.跑步里程.骑行里程等.运动APP与运动类的穿戴设备借助传感器.地图.GPS定位等技术,收集好运动数据以后,通过与互联网社交功能结合,产生 ...
- mysql数据漂移_数据库漂移-和数据库漂移相关的内容-阿里云开发者社区
MySQL双主一致性架构优化 | 架构师之路 一.双主保证高可用 MySQL数据库集群常使用一主多从,主从同步,读写分离的方式来扩充数据库的读性能,保证读库的高可用,但此时写库仍然是单点. 在一个My ...
- 阿里 postgresql mysql_如何将PostgreSQL与MySQL相结合,实现1+12的组合拳?(下)-阿里云开发者社区...
查看上篇文章,点击这里. (4)无死角全加密 前面讲了一下我们有一个无死角全加密的一个版本,是一个特殊的版本.这个版本也是跟跟达摩院合作输出的一个版本.它能够防网络攻击,数据库攻击,操作系统攻击,存储 ...
- mysql导出入数据库报错_mysql数据库导出导入数据库的搜索结果-阿里云开发者社区...
mysql 数据库导入\导出(总结备忘) 数据库的基本导入\导出的命令 是 mysqldump 和 source 在linux下直接用命令行操作就可以 在windows下 一般情况下有两种方法一个也是 ...
- mysql跨平台迁移复制_手工 XTTS CPT 迁移-跨平台迁移数据库-阿里云开发者社区
-- xtts 跨平台迁移数据库 -- 步骤: 1.初始化参数设置: 2.将源端数据文件传输到目标系统: 3.转换数据文件为目标系统的字节序: 4.在源端创建增量备份,并传输到目标端: 5.在目标端恢 ...
- mysql注册slave_创建slave库?spm=a2c4e.11155472的搜索结果-阿里云开发者社区
云原生必备知识: 应用储存 所属技术领域: 云原生 | 名词定义 | 由于容器本身是非持久化的,因此需要解决在容器中运行应用程序遇到的一些问题.首先,当容器崩溃时,kubelet将重新启动容器,但是写 ...
- mysql第二天无法连接_jdbc 连接mysql 第二天就连接不成功,什么原因?-问答-阿里云开发者社区-阿里云...
情况是这样,我做的是一个SSH项目,中间需要连接另个一个项目数据库查询数据,也算是双数据源,我就建了个DBUtil类 创建 Connection对象,每天重启起来了 第二天早上页面就访问不了了 我怀疑 ...
最新文章
- 考研最惨专业排行榜,你上榜了吗?
- 数组、链表、Hash(转)
- 治标不治本:POI Ptg错误的解决方法
- android跑步软件,手机跑步软件哪个好_安卓手机跑步记录软件_手机跑步app【最新】-太平洋电脑网...
- kvm虚拟机设置万兆网卡_SR-IOV 10Gb 万兆网卡支持
- 博客园“图灵杯”第3届博问大赛比赛结果
- matlab 矩阵引用,MATLAB矩阵生成、引用
- 树莓派系统的安装、初步配置与远程访问
- 360杀毒引发的DLL调用异常
- 查看静态库支持的CPU架构
- dns服务器迁移方法简单说明
- ai 实用新型专利_专利制度协调AI创造的创新
- 获取音频频响和失真_专业音响设备_音频功放失真的四大要点及改善方法
- tmdb数据集_数据科学第2部分的数据管道tmdb api数据搜寻器
- RQNOJ 石子合并
- linux让别人电脑蓝屏,愚人节必备,教你制作整人神器,用代码实现计算机蓝屏...
- 《尚书》全文、注释及译文(2)
- LSF COMMAND bhist
- 什么是Java垃圾回收器
- 微信气泡主题设置_微信气泡主题华为手机要怎么弄 华为手机微信气泡主题设置方法介绍...
热门文章
- ActiveMQ 即时通讯服务 入門指南及淺析
- js--window关闭事件
- java中的List排序[转]
- java struts2下载zip_Struts2多文件下载
- 宿命传说2之女神召唤java_热血传奇:传奇那些传说中的秘密,连骨灰级的玩家都未必知道...
- pythonos模块介绍_python的os模块fnmatch模块介绍
- vscode中控制台不能输入_vscode调试时如何在控制台输入
- 双十一要来了,如何设计出那些牛X的促销页面?
- 手机活动促销宣传海报,如何设计更有吸引力?
- PSD分层模板素材|电商页面这样设计,转化率成倍提高!