首页 > 数据库 >故障分析 | MySQL死锁案例分析

故障分析 | MySQL死锁案例分析

时间:2022-12-20 12:00:10浏览次数:40  
标签:分析 insert dl lock 死锁 MySQL c2 id

一  背景

死锁,其实是一个很有意思也很有挑战的技术问题,大概每个DBA和部分开发同学都会在工作过程中遇见过。本次分享的死锁案例更新不存在的记录加上 X GAP lock 和 insert 的意向锁冲突。希望能够对想了解死锁的朋友有所帮助。

二  案例分析

2.1  业务逻辑

业务逻辑: 业务需要并发不同数据(insert+update),首先是更新记录,如果发现更新的 affect rows 为 0 ,然后就执行插入,如果插入失败,再执行更新。因此存在并发的情况下,两个事务都执行了更新,affect rows 为 0 ,然后有进行并发插入相同记录的情况。

2.2 环境说明

数据库版本 8.0.30

事务隔离级别   REPEATABLE-READ

create table dl(
id int auto_increment primary key,
c1 int not null ,
c2 int not null,
c3 int not null,
unique key uc1(c1),
unique key uc2(c2));

insert into dl(c1,c2,c3) values(2,0 ,2),(5,5,5);

2.3 测试用例

 

 

 

2.4 死锁日志

------------------------
LATEST DETECTED DEADLOCK
------------------------
*** (1) TRANSACTION:
TRANSACTION 1422661, ACTIVE 51 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 4 lock struct(s), heap size 1128, 3 row lock(s), undo log entries 1
MySQL thread id 3149, OS thread handle 140261085611776, query id 3267 localhost msandbox update
insert into dl(c1,c2,c3) values(3,2,2)

*** (1) HOLDS THE LOCK(S):
RECORD LOCKS space id 50 page no 5 n bits 72 index uc1 of table `test`.`dl` trx id 1422661 lock_mode X locks rec but not gap
Record lock, heap no 4 PHYSICAL RECORD: n_fields 2; compact format; info bits 0

*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 50 page no 6 n bits 72 index uc2 of table `test`.`dl` trx id 1422661 lock_mode X locks gap before rec insert intention waiting
Record lock, heap no 3 PHYSICAL RECORD: n_fields 2; compact format; info bits 0

*** (2) TRANSACTION:
TRANSACTION 1422664, ACTIVE 45 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 1128, 2 row lock(s), undo log entries 1
MySQL thread id 3152, OS thread handle 140261086668544, query id 3268 localhost msandbox update
insert into dl(c1,c2,c3) values(3,2,2)

*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 50 page no 6 n bits 72 index uc2 of table `test`.`dl` trx id 1422664 lock_mode X locks gap before rec
Record lock, heap no 3 PHYSICAL RECORD: n_fields 2; compact format; info bits 0

*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 50 page no 5 n bits 72 index uc1 of table `test`.`dl` trx id 1422664 lock mode S waiting
Record lock, heap no 4 PHYSICAL RECORD: n_fields 2; compact format; info bits 0

*** WE ROLL BACK TRANSACTION (2)

2.5 死锁分析

  1. sess1 在 T3 时刻执行了更新,affect rows 为 0 ,在c2的(2,5) 区间中加了 X ,GAP锁。
  1. sess2 在 T4 时刻执行了更新,affect rows 为 0 ,同样在在c2的(0,3)区间中加了GAP锁 lock_mode X locks gap before rec ,GAP 锁和 GAP 锁相互兼容,因此 sess1 和 sess2 不会发生等待。

            

 

 

 

  1. sess1 在 T5 时刻执行了插入,由于插入记录 c2 =2 的时候需要申请插入意向锁(insert intention lock) ,而 insert intention lock 锁和已存在的 (0,3) 的 lock_mode X locks gap before rec insert intention waiting是冲突的,也就是 sess1 需要等待 sess2 在T4持有的 GAPX 锁,发生了等待。

            

 

 

  1. sess2 在 T6 时刻执行了插入,由于插入的时候需要申请插入意向锁(insert intention lock),同样需要等待 Sess1 在 T3 持有的 GAP 锁,两个会话循环等待对方释放锁,因此导致死锁。

感兴趣的朋友可以自做测试,每一步操都打印 show engine innodb status 查看当前事务的锁等待事件。或者执行 SQL 查询当前事务持有或者等待的锁select ENGINE_TRANSACTION_ID, index_name, lock_type, lock_mode, LOCK_STATUS, lock_data from performance_schema.data_locks;

2.6 如何解决

将 update + insert 合并为 insert on duplicate key 的方式,避免同一个事务申请多个锁。

小结

敲黑板,重点: 死锁是因为不同事务对表记录加锁的顺序不一致导致相互等待对方持有的锁导致的。大家在分析死锁的时候能基于该原则去分析理清业务的 sql 逻辑和执行顺序,基本上都能解决大部分的问题场景。另外文章的最后我们再次复习一下  MySQL 的加几个基本原则,方便大家后面遇到死锁案例进行分析:
原则 1:加锁的基本单位是 next-key lock。

原则 2:查找过程中访问到的对象才会加锁。

优化 1:索引上的等值查询,给唯一索引加锁的时候,next-key lock 退化为行锁。

优化 2:索引上的等值查询,向右遍历时且最后一个值不满足等值条件的时候,next-key lock 退化为间隙锁。

一个 bug:唯一索引上的范围查询会访问到不满足条件的第一个值为止。

在读提交隔离级别下还有一个优化,即:语句执行过程中加上的行锁,在语句执行完成后,就要把“不满足条件的行”上的行锁直接释放了,不需要等到事务提交。

标签:分析,insert,dl,lock,死锁,MySQL,c2,id
From: https://www.cnblogs.com/harda/p/16993886.html

相关文章

  • MySQL锁等待超时一例分析
    1、问题现象开发反馈某业务持续性报锁等待超时,相关错误信息如下:Lock wait timeout exceeded; try restarting transaction为了能精确定位问题,继续询问开发有没有......
  • 【验证码逆向专栏】某片滑块、点选验证码逆向分析
    声明本文章中所有内容仅供学习交流使用,不用于其他任何目的,不提供完整代码,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后......
  • 基于jsp+servlet+mysql简单的实现了商品的增删改查
    @目录一、系统介绍二、功能展示1.商品主页2.商品添加3.商品修改4.商品查询5.商品删除三、数据库四、其它系统一、系统介绍系统主要功能:简单的实现了商品的增删改查环境......
  • 实例说明optimize table在优化mysql时很重要
    实例说明optimizetable在优化mysql时很重要张映发表于2011-03-07分类目录:mysql标签:mysql,optimizetable,优化今天在看CU的时候,发现有人问有关optimize来......
  • [MySQL]SELECT list is not in GROUP BY clause and contains nonaggregated column..
    项目在windows上运行正常,迁移到Linux系统上就出现了这个错,经查是由于本人sql不规范且恰好mysql的sql_mode启用了only_full_group_by,当sql语句中使用了分组查询,并且查询的字......
  • 【验证码逆向专栏】某片滑块、点选验证码逆向分析
    声明本文章中所有内容仅供学习交流使用,不用于其他任何目的,不提供完整代码,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切......
  • MySQL使用--存储过程篇
    查看存储过程:select`name`frommysql.procwheredb='your_db_name'and`type`='PROCEDURE'SHOWprocedurestatus;查看存储过程的创建代......
  • MySQL使用--通用操作篇
    服务启动:netstartmysql(windows启动)"/etc/rc.d/init.d/mysqldstart"(linux启动)用户登录:mysql[mydb]-h127.0.0.1-uroot-ppassword;常用统计......
  • MySQL使用--表操作篇
    查看表描述:DESCRIBEMYTABLE;创建表:CREATETABLE[IFNOTEXISTS]表名称(列名称1数据类型[属性][索引],列名称2数据类型[属性][索引],列名称......
  • MySQL使用--内建函数篇
    一.字符串类:CHARSET(str)//返回字串字符集CONCAT(string2[,...])//连接字串INSTR(string,substring)//返回substring首次在string中出现的......