并发delete+insert duplicate-key冲突导致死锁
死锁案例
简化后的死锁场景如下
环境: mysql5.7,事务隔离级别REPEATABLE-READ
表结构
CREATE TABLE `t4` ( `a` int(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`a`) ) ENGINE=InnoDB 数据: mysql> select * from t4; +---+ | a | +---+ | 1 | +---+
并发事务
T1 | T2 |
---|---|
begin; | begin |
delete from t4 where a = 1;//ok, 0 rows affected | |
delete from t4 where a = 1; //wating,被阻塞 | |
insert into t4 values(1);//Query OK, 1 row affected (0.01 sec) | |
ERROR 1213 (40001): Deadlock found when trying to get lock; |
从上面可以看出,并发事务执行delete,T2等待,T1再执行insert相同value的数据时出现死锁。
死锁分析
死锁原因
insert时如果数据出现duplicate key,会加LOCK_S锁,类型为NEXT-KEY LOCK,此时事务2已经在申请record lock X锁,在申请队列中了,事务1再加NEXT-KEY LOCK S锁则需要等待事务2提交,这就造成了相互等待。
加锁分析
- T2 delete语句需要等待记录上的X锁;
- 普通insert时,其加锁过程为先在插入间隙上获取插入意向锁,插入数据后再获取插入行上的排它锁。由于这里T1 insert的数据检测到duplicate key,会加S锁(如果扫描到的记录被标记删除时,也会加S 锁),且针对主键索引加LOCK_ORDINARY类型的记录锁(NEXT-KEY LOCK),而NEXT-KEY LOCK与record互斥 。
另外,如果delete的where子句没有满足条件的记录,而对于不存在的记录 并且在RR级别下,delete加锁类型为gap lock。可以参考我的这篇博客https://my.oschina.net/hebaodan/blog/1835966
在RC级别测试上述场景无死锁发生。
死锁解决
- 避免出现按某个key delete后又插入相同key的场景,规避insert数据duplicate key的问题
- 如果非特殊需求修改为非唯一索引
- 通过其他手段如分布式锁实现串行化处理
附:死锁日志
*** (1) TRANSACTION: TRANSACTION 11074, ACTIVE 11 sec starting index read mysql tables in use 1, locked 1 LOCK WAIT 2 lock struct(s), heap size 1136, 1 row lock(s) MySQL thread id 10, OS thread handle 123145442168832, query id 160 localhost 127.0.0.1 root updating delete from t4 where a = 1 *** (1) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 68 page no 3 n bits 72 index PRIMARY of table `aliyun`.`t4` trx id 11074 lock_mode X locks rec but not gap waiting Record lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 32 0: len 4; hex 80000001; asc ;; 1: len 6; hex 000000002b41; asc +A;; 2: len 7; hex 2e000001dc13c4; asc . ;; *** (2) TRANSACTION: TRANSACTION 11073, ACTIVE 40 sec inserting mysql tables in use 1, locked 1 3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1 MySQL thread id 9, OS thread handle 123145442725888, query id 161 localhost 127.0.0.1 root update insert into t4 values(1) *** (2) HOLDS THE LOCK(S): RECORD LOCKS space id 68 page no 3 n bits 72 index PRIMARY of table `aliyun`.`t4` trx id 11073 lock_mode X locks rec but not gap Record lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 32 0: len 4; hex 80000001; asc ;; 1: len 6; hex 000000002b41; asc +A;; 2: len 7; hex 2e000001dc13c4; asc . ;; *** (2) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 68 page no 3 n bits 72 index PRIMARY of table `aliyun`.`t4` trx id 11073 lock mode S waiting Record lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 32 0: len 4; hex 80000001; asc ;; 1: len 6; hex 000000002b41; asc +A;; 2: len 7; hex 2e000001dc13c4; asc . ;; *** WE ROLL BACK TRANSACTION (1)
参考
https://dev.mysql.com/doc/refman/8.0/en/innodb-locks-set.html

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
嵌套容器 —— 在 Podman 容器内构建并运行 Buildah
去年圣诞节,笔者送给妻子一套俄罗斯套娃。它们由一个木偶组成,每个木偶打开后是另外一个更小的木偶,直到最小那个出现。这个概念让我想到了嵌套容器。 我想我或许可以尝试用 Podman 来构建自己的嵌套容器,我可以在容器中基于Buildah做开发,也可以继续创建 Buildah 容器和映像。一旦创建了 Podman 容器,就可以将它移到任意支持 Podman 的 Linux 系统上。然后使用 Buildah 进行开发。本文中我将详细介绍整个过程。 环境准备 本文是在一个全新安装的 Fedora 29 虚拟机上进行的,系统上安装了最新版本的 Podman 和container-selinux ,安装命令为:dnf -y install podman container-selinux --enablerepo updates-testing。相应版本是Podman v1.1.2 和 container-selinux 2.85-1. 不管是容器,还是容器中的容器都要用到 fuse-overlayfs,当尝试将其相应目录安装在一起时会有很多麻烦。因此,第一步应该为容器创建一个目录,这里我们将其命...
- 下一篇
论JVM爆炸的几种姿势及自救方法
前言 如今不管是在面试还是在我们的工作中,OOM总是不断的出现在我们的视野中,所以我们有必要去了解一下导致OOM的原因以及一些基本的调整方法,大家可以通过下面的事例来了解一下什么样的代码会导致OOM,帮助我们以后在工作中能够通过异常信息来判断是JVM里面哪个区域出现了问题。 先介绍一下笔者的相关编码环境。 jdk:java version "1.8.0_121" ide:IntelliJ IDEA 2019.1 (Community Edition) 正文 1.Java堆溢出 Java中的堆存储的都是对象实例,当我们不断的创建对象,而GC的时候又不能回收,当存储的对象大小超过了-Xmx的值,这时候则会出现OutOfMemoryError.[-XX:+HeapDumpOnOutOfMemoryError]参数可以让jvm出现内存溢出的时候dump出内存堆转储快照。 /** * VM Args: -Xms10m -Xmx10m -XX:+HeapDumpOnOutOfMemoryError * @author wangzenghuang */ public class HeapOOMDem...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Red5直播服务器,属于Java语言的直播服务器
- CentOS关闭SELinux安全模块
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- SpringBoot2整合Redis,开启缓存,提高访问速度
- Hadoop3单机部署,实现最简伪集群
- SpringBoot2更换Tomcat为Jetty,小型站点的福音