一、死锁案例

MySQL版本:Percona MySQL Server 5.7.19
隔离级别:可重复读(RR)
业务逻辑:并发下按某个索引字段先delete记录,再insert记录

比如:

begin;
delete from tb where order_id = xxx;
insert into tb(order_id) values(xxx);
commit;

二、MySQL锁基本概念

S:共享锁(行级锁)
X:排他锁(行级锁)
IS:意向共享锁(表级锁)
IX:意向排他锁(表级锁)

以上4种锁的兼容性见下表:

锁模式兼容性表

  • gap锁与gap锁之间不冲突
  • rec insert intention(插入意向锁)与gap锁冲突。

三、模拟复现死锁

打开参数,从innodb status获取更多的锁信息。
set GLOBAL innodb_status_output_locks=ON;

表结构:

 CREATE TABLE `tb` (`order_id` int(11) DEFAULT NULL,KEY `idx_order_id` (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

表中数据:

mysql> select * from tb;
+----------+
| order_id |
+----------+
|       10 |
|       20 |
+----------+
2 rows in set (0.00 sec)

事务执行步骤:

session1 session2
begin  
  begin
delete from tb where order_id=15;  
  delete from tb where order_id=15;
  insert into tb select 15;(等待锁)
insert into tb select 15;(死锁)  
  1. 当session1执行delete from tb where order_id=15;,由于条件order_id=15的记录不存在,session1 获得2个锁结构,分别是意向排他锁IX(表级锁)、gap锁(行级锁),如下:
---TRANSACTION 1055191443, ACTIVE 20 sec
2 lock struct(s), heap size 1136, 1 row lock(s)
MySQL thread id 315642, OS thread handle 139960342456064, query id 150462030 localhost root
TABLE LOCK table `db`.`tb` trx id 1055191443 lock mode IX
RECORD LOCKS space id 1337 page no 4 n bits 72 index idx_order_id of table `db`.`tb` trx id 1055191443 lock_mode X locks gap before rec
  1. 当session2执行delete from tb where order_id=15;,同样由于order_id=15的记录不存在,session2 也获得2个锁结构,分别是意向排他锁IX(表级锁)、gap锁(行级锁),如下:
---TRANSACTION 1055191444, ACTIVE 3 sec
2 lock struct(s), heap size 1136, 1 row lock(s)
MySQL thread id 315336, OS thread handle 139960562685696, query id 150462412 localhost root
TABLE LOCK table `db`.`tb` trx id 1055191444 lock mode IX
RECORD LOCKS space id 1337 page no 4 n bits 72 index idx_order_id of table `db`.`tb` trx id 1055191444 lock_mode X locks gap before rec
  1. 当session2执行insert into tb select 15;, session2 已经获取到IX锁,gap锁,等待 rec insert intention(插入意向锁)
---TRANSACTION 1055191444, ACTIVE 68 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1
MySQL thread id 315336, OS thread handle 139960562685696, query id 150462778 localhost root executing
insert into tb select 15
------- TRX HAS BEEN WAITING 2 SEC FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 1337 page no 4 n bits 72 index idx_order_id of table `db`.`tb` trx id 1055191444 lock_mode X locks gap before rec insert intention waiting
------------------
TABLE LOCK table `db`.`tb` trx id 1055191444 lock mode IX
RECORD LOCKS space id 1337 page no 4 n bits 72 index idx_order_id of table `db`.`tb` trx id 1055191444 lock_mode X locks gap before rec
RECORD LOCKS space id 1337 page no 4 n bits 72 index idx_order_id of table `db`.`tb` trx id 1055191444 lock_mode X locks gap before rec insert intention waiting
  1. 当session1执行insert into tb select 15;,session1 已获取到IX锁,gap锁, 等待rec insert intention(插入意向锁), session1, session2 都在等待插入意向锁, 插入意向锁与gap锁冲突,双方都没有释放gap锁,又都在等待插入意向锁,死锁发生。
LATEST DETECTED DEADLOCK
------------------------
2018-11-03 17:15:11 0x7f4b0e7ea700
*** (1) TRANSACTION:
TRANSACTION 1055191444, ACTIVE 135 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1
MySQL thread id 315336, OS thread handle 139960562685696, query id 150462778 localhost root executing
insert into tb select 15
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 1337 page no 4 n bits 72 index idx_order_id of table `db`.`tb` trx id 1055191444 lock_mode X locks gap before rec insert intention waiting
*** (2) TRANSACTION:
TRANSACTION 1055191443, ACTIVE 201 sec inserting, thread declared inside InnoDB 5000
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 315642, OS thread handle 139960342456064, query id 150463172 localhost root executing
insert into tb select 15
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 1337 page no 4 n bits 72 index idx_order_id of table `db`.`tb` trx id 1055191443 lock_mode X locks gap before rec
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 1337 page no 4 n bits 72 index idx_order_id of table `db`.`tb` trx id 1055191443 lock_mode X locks gap before rec insert intention waiting
*** WE ROLL BACK TRANSACTION (2)

四、案例扩展

以上死锁案例,业务代码逻辑是多线程并发下,有可能多个线程会执行相同order_id的job,比如两个线程执行的order_id 都是15。
另外一种情况,多个线程间,不会执行到相同order_id的情况,也可能发生死锁。比如一个线程order_id=15,另外一个线程order_id=16,如下所示:

事务执行步骤:

session1 session2
begin  
  begin
delete from tb where order_id=15;  
  delete from tb where order_id=16;
  insert into tb select 16;(等待锁)
insert into tb select 15;(死锁)  

锁情况与上述相同,不再赘述,死锁信息如下:

LATEST DETECTED DEADLOCK
------------------------
2018-11-03 17:28:30 0x7f4b0e667700
*** (1) TRANSACTION:
TRANSACTION 1055191450, ACTIVE 18 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1
MySQL thread id 316221, OS thread handle 139960338228992, query id 150467652 localhost root executing
insert into tb select 16
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 1337 page no 4 n bits 72 index idx_order_id of table `db`.`tb` trx id 1055191450 lock_mode X locks gap before rec insert intention waiting
*** (2) TRANSACTION:
TRANSACTION 1055191449, ACTIVE 28 sec inserting, thread declared inside InnoDB 5000
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 316222, OS thread handle 139960340870912, query id 150467681 localhost root executing
insert into tb select 15
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 1337 page no 4 n bits 72 index idx_order_id of table `db`.`tb` trx id 1055191449 lock_mode X locks gap before rec
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 1337 page no 4 n bits 72 index idx_order_id of table `db`.`tb` trx id 1055191449 lock_mode X locks gap before rec insert intention waiting
*** WE ROLL BACK TRANSACTION (2)

五、解决方案

  1. 修改隔离级别为提交读(RC)
  2. 修改业务代码逻辑,删除记录之前,先select,确认该记录存在,再执行delete删除该记录。

MySQL死锁案例分:先delete,再insert,导致死锁相关推荐

  1. Mysql自增列,并发插入时导致死锁的问题

    背景: 有一张表需要每天定时迁移数据,采用的SQL如下(表名已调整) insert into data_cache ( customerID,organizationID,createTime)( s ...

  2. delete语句居然导致死锁了?

    今日份,运营突然联系说创建优惠券无响应,我还调侃他说,浏览器不兼容,你换个浏览器试试呢?结果试了依旧不行,找问题吧. 先看request.info日志,看结果返回啥了? 这--死锁了?Lock wai ...

  3. mysql先删后增并发时出现死锁_MySQL死锁案例分析一(先delete,再insert,导致死锁)...

    一.死锁案例 MySQL版本:Percona MySQL Server 5.7.19 隔离级别:可重复读(RR) 业务逻辑:并发下按某个索引字段先delete记录,再insert记录 比如:begin ...

  4. Innodb锁系统 Insert/Delete 锁处理及死锁示例分析

    A.INSERT 插入操作在函数btr_cur_optimistic_insert->btr_cur_ins_lock_and_undo->lock_rec_insert_check_an ...

  5. MySQL 5.6.35 索引优化导致的死锁案例解析

    一.背景 随着公司业务的发展,商品库存从商品中心独立出来成为一个独立的系统,承接主站商品库存校验.订单库存扣减.售后库存释放等业务.在上线之前我们对于核心接口进行了压测,压测过程中出现了 MySQL ...

  6. mysql 秀出两个相关联的表中满足条件的内容_这六个 MySQL 死锁案例,能让你理解死锁的原因!...

    点击蓝色"架构文摘"关注我哟 加个"星标",每天上午 09:25,干货推送! 来源:王啸tr1912  |  https://blog.csdn.net/tr1 ...

  7. 数据库:分享六个 MySQL 死锁案例,能让你理解死锁的原因!

    正文 最近总结了一波死锁问题,和大家分享一下,我这也是从网上各种浏览博客得来,希望原作者见谅,参考博客文末下方. Mysql 锁类型和加锁分析MySQL有三种锁的级别:页级.表级.行级. 表级锁:开销 ...

  8. 由MySQL加锁机制引发的死锁案例分析

    ​ 1.死锁案例 --建表 CREATE TABLE t1(`id` int(11) NOT NULL,`value` int(11) NOT NULLPRIMARY KEY (`id`),KEY ` ...

  9. mysql使用触发器,delete、insert、update触发器

    mysql5之后的版本才支持触发器. 想要某条语句在事件发生时自动执行,可使用触发器. 例如下面场景: 每当增加一条顾客数据时,都检查其号码格式是否正确.每订购一个产品时,都从库存中减去订购的数量无论 ...

最新文章

  1. 尚硅谷学Javaweb,关于正则表达式笔记
  2. 机器学习算法如何调参?这里有一份神经网络学习速率设置指南
  3. pyqt根据名字获取控件
  4. Codeforces Round #476 (Div. 2) C. Greedy Arkady
  5. 什么是中国1号信令?
  6. 【剑指offer】面试题54:二叉搜索树的第k大节点(java)
  7. JdbcTemplate(操作数据库-查询返回对象、查询返回集合)
  8. F - A Simple Problem with Integers(线段树)
  9. SAP License:SAP成本收集器两则
  10. 40个非常有创意的国外LOGO欣赏(上)
  11. pd虚拟机:mac支持安装Windows应用
  12. SharePoint Foundation 2013安装-1:先决条件准备
  13. Bilibili宋红康老师MySQL高级篇笔记-架构篇(有完整的md格式笔记,迟点整理好会挂链接)
  14. C/C++编程:字符串拼接
  15. 【倒计时1天】PPP全球数字资产投资峰会-中国区北京首站之金融科技区块链支持可持续发展...
  16. 逆滲透水與蒸餾水最不能喝
  17. python解魔方程序_写一个解二阶魔方的程序
  18. promise获取所有文件路径_python使用os.listdir和os.walk获得文件的路径
  19. Python实现二维离散卷积运算
  20. 科技的成就(三十九)

热门文章

  1. response.setHeader各种用法 .
  2. C/C++内存分配方式 .
  3. java如何开发bpm系统_java工作流bpm开发ERP实例
  4. linux环境没有bzip2,Linux系统中安装使用Bzip2来压缩文件的方法讲解
  5. mysql默认数据库名称,默认的MySQL数据库名称
  6. kubernetes英语怎么读_陷阱英语单词怎么读?
  7. php要掌握的内容,入门PHPer需要掌握的哪些内容?
  8. mysql binlog过期策略_MySQL binlog日志优化方案
  9. 病案编码员需要计算机的什么知识,如何成为一名优秀的病案编码员?
  10. 4g模块注册上网 移远_Openwrt支持移远4G模块过程记录