近日遇到一个比较奇怪的deadlock错误, 错误详情:

Deadlock found when trying to get lock; try restarting transaction; nested exception is com.ibatis.common.jdbc.exception.NestedSQLException...

跟踪代码后最终定位到一段业务逻辑:

delete from A where no = $no;
insert into A(no, value) values($no, "value");

印象中mysql一直是使用行级锁, 为什么此处在并发时会发生死锁呢? 唯一的解释是mysql在这边锁住的不只一行数据.

简单搜索之后, 发现mysql的锁分为三种(按照锁定的行数划分):
1.record lock:记录锁,也就是仅仅锁着单独的一行
2.gap lock:区间锁,仅仅锁住一个区间(注意这里的区间都是开区间,也就 是不包括边界值,至于为什么这么定义?innodb官方定义的)
3.next-key lock:record lock+gap lock,所以next-key lock也就半开半闭区间,且是下界开,上界闭。(为什么这么定义?innodb官方定义的)

由于此处是在明确指定了no=XX的情况下抛出了死锁异常, 并且no建立的是普通索引, 所以此处mysql使用的应该是next-key lock(查看何种情况下使用何种锁 https://dev.mysql.com/doc/refman/5.7/en/innodb-locks-set.html).

下面来举个手册上的例子看看next-key lock是如何上锁的。假如一个索引的行有10,11,13,20
那么可能的next-key lock的包括:
(无穷小, 10]
(10,11]
(11,13]
(13,20]
(20, 无穷大)

下面分析何种情况下会发生死锁.
结合业务逻辑, 执行新增操作时也会执行一样的逻辑, 先进行delete.
例如,现在表student中有四条数据:

Image 1

现在要新增一条数据, no = 21, 这时候会先进行delete, 线程会锁住(20, 无穷大)这块区间, 加入这个时候另一个线程正在新增另一条数据 no = 22, 线程也会锁住(20, 无穷大)这块区间就会发生死锁.

下面看具体实验:
创建一张表student.

CREATE TABLE `student` (`id` int(11) NOT NULL AUTO_INCREMENT,`no` int(11) DEFAULT NULL,`name` varchar(255) DEFAULT NULL,PRIMARY KEY (`id`),KEY `idx_no` (`no`)
) ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=latin1

插入数据:

INSERT INTO student (no,name) VALUES(10, "Jim");
INSERT INTO student (no,name) VALUES(11, "Kimi");
INSERT INTO student (no,name) VALUES(13, "Tom");
INSERT INTO student (no,name) VALUES(20, "Mike");

Image 2

执行两个事务:
session 1:

begin;
delete from student where no = 21;

session 2:

begin;
delete from student where no = 22;

此处解释一下, 此时,session 1和session 2都会对区间(20, 无穷大)加锁, 而区间锁只是用来防止其他事务在区间中插入数据,区间x锁 与区间S锁效果是一样的(只要不是插入操作), 因此两个session都会持有锁.

参考:https://dev.mysql.com/doc/refman/5.1/en/innodb-record-level-locks.html
Gap locks in InnoDB are “purely inhibitive”, which means they only stop other transactions from inserting to the gap. Thus, a gap X-lock has the same effect as a gap S-lock.

继续执行:
session 1:

INSERT INTO student (no,name) VALUES(21, "Zhoubing");

此时session 1阻塞(因为session 2持有区间锁), 如图:

Image 3

session 2:

INSERT INTO student (no,name) VALUES(22, "Zhoubing");

此时session 2死锁(因为session 1持有区间锁), 如图:

Image 4

.

总结, delete之后进行insert有可能发生死锁, 因为delete可能会持有区间锁, 而区间锁是可重入的(只要不是插入数据).

解决方案:
将事务隔离级别将为read commit.

参考资料:
1.Next-Key Locks
2.Locks Set by Different SQL Statements in InnoDB

一次DeleteInsert引发的Mysql死锁相关推荐

  1. DeleteInsert引发的Mysql死锁

    近日遇到一个比较奇怪的deadlock错误, 错误详情: Deadlock found when trying to get lock; try restarting transaction; nes ...

  2. MySQL 死锁专题问题处理

    1.Delete删除不存在的数据导致死锁 原文:Delete&Insert引发的Mysql死锁 mysql的锁分为三种(按照锁定的行数划分): 1.record lock:记录锁,也就是仅仅锁 ...

  3. mysql 死锁监视器_并发基础知识:死锁和对象监视器

    mysql 死锁监视器 本文是我们名为Java Concurrency Essentials的学院课程的一部分. 在本课程中,您将深入探讨并发的魔力. 将向您介绍并发和并发代码的基础知识,并学习诸如原 ...

  4. 记录一次mysql死锁

    一,死锁发现 项目中有一个接口包含更新操作1,后面发现更新失败,通过查看应用程序日志,发现发生了死锁 sql 1 如下 1.最初版本根据id为条件,更新(plan_start_time 二级索引) u ...

  5. MySQL - 死锁的产生及解决方案

    MySQL - 死锁的产生及解决方案 1. 死锁与产生死锁的四个必要条件 1.1 什么是死锁 1.2 死锁产生的4个必要条件 2. 死锁案例 2.1 表锁死锁 2.2 行锁死锁 2.3 共享锁转换为排 ...

  6. mysql死锁介绍以及解决

    什么是死锁 死锁是2+个线程在执行过程中, 因争夺资源而造成的相互等待的现象,若无外力作用,它们将无法推进下去. 死锁产生的4个必要条件 互斥条件 指进程对所分配的资源进行排他性使用,即一段时间内某资 ...

  7. java mysql死锁_记一次线上mysql死锁分析(一)

    记录一次比较诡异的mysql死锁日志.系统运行几个月来,就在前几天发生了一次死锁,而且就只发生了一次死锁,整个排查过程耗时将近一天,最后感谢我们的DBA大神和老大一起分析找到原因. 诊断死锁 借助于我 ...

  8. mysql查询死锁的次数_一次神奇的MySQL死锁排查记录

    一次神奇的MySQL死锁排查记录 发布时间:2020-08-29 00:50:26 来源:脚本之家 阅读:135 作者:咖啡拿铁 背景 说起Mysql死锁,之前写过一次有关Mysql加锁的基本介绍,对 ...

  9. MySQL死锁如何处理

    转载自  MySQL死锁如何处理 前提 笔者负责的一个系统最近有新功能上线后突然在预警模块不定时报出MySQL死锁导致事务回滚.幸亏,上游系统采用了异步推送和同步查询结合的方式,感知到推送失败及时进行 ...

最新文章

  1. 分类算法之贝叶斯网络(Bayesian networks)
  2. 数据科学和机器学习中使用的最多的20个R语言包
  3. java web 来源页_JavaWeb 分页实现
  4. Cortex-M3基本知识点(手册)
  5. 斑马Zebra驱动下载
  6. 英雄联盟服务器维护3月17,英雄联盟将于3月17日凌晨2点开始进行全区停机维护...
  7. Linux RAID磁盘阵列
  8. JavaScript基础(六)面向对象
  9. 容器入门(1) - 安装和使用Docker Registry
  10. java main spring_分享通过在java main函数中执行spring的代码
  11. opengl笔记——OpenGL好资料备忘
  12. TIM无法打开本地文件
  13. 淘宝/天猫优惠券获取API 接口
  14. Android Studio 华为手机真机调试
  15. 运用regedit编辑器恢复清空回收站之后的文件
  16. 小熊派折叠开发板(一)- 开发板介绍
  17. hi3559Av100 行车记录仪系统框图
  18. 面试官:谈谈分库分表吧?
  19. 【数据结构和算法】 八大排序算法详解
  20. 阅读JEECG源码,关于登录,密码加密

热门文章

  1. (*长期更新)软考网络工程师学习笔记——Section 4 物理层的其它知识
  2. 计算机网络实验(华为eNSP模拟器)——第二章 VRP通用路由平台介绍
  3. 消除左递归c++代码_【每日算法Day 85】图解算法:一行代码解决约瑟夫环的变体...
  4. Nginx使用之location和rewrite用法
  5. clickhouse原理解析与应用实践_Hybrid App (混合应用) 技术全解析 方案原理篇
  6. python之.py生成.exe可执行文件
  7. java与c/c++进行socket通信的一些问题(2)
  8. java 桥梁模设计,Java设计模式学习篇(九)桥接设计模式
  9. python交换两列的位置_如何更改 pandas dataframe 中两列的位置
  10. java中system_《java中System类》 | 学步园