前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >两次死锁的分析

两次死锁的分析

作者头像
十毛
发布2020-09-18 10:01:39
9670
发布2020-09-18 10:01:39
举报

最近业务上连续出现了两次死锁逻辑,两次都是特别简单的SQL语句,分析后才发现自己对InnoDB加锁了解得太浅了。

表结构

代码语言:javascript
复制
CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(64) NOT NULL,
  `age` int(11) DEFAULT NULL,
  `deleted` int(22) DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

主键id和唯一键name

死锁场景一

  • SQL语句
代码语言:javascript
复制
select * from user where name='tenmao' for update;
insert into user(`name`) values('tenmao');
  • 死锁日志
代码语言:javascript
复制
------------------------
LATEST DETECTED DEADLOCK
------------------------
2020-09-16 20:23:21 0x7f4b8b596700
*** (1) TRANSACTION:
TRANSACTION 425593, ACTIVE 21 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 65439, OS thread handle 139962440095488, query id 2992052 localhost maibao update
insert into user(`name`) values('tenmao')
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 370 page no 4 n bits 72 index uk_name of table `tenmao`.`user` trx id 425593 lock_mode X insert intention waiting
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
 0: len 8; hex 73757072656d756d; asc supremum;;

*** (2) TRANSACTION:
TRANSACTION 425594, ACTIVE 12 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 65440, OS thread handle 139962437166848, query id 2992053 localhost maibao update
insert into user(`name`) values('tenmao')
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 370 page no 4 n bits 72 index uk_name of table `tenmao`.`user` trx id 425594 lock_mode X
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
 0: len 8; hex 73757072656d756d; asc supremum;;

*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 370 page no 4 n bits 72 index uk_name of table `tenmao`.`user` trx id 425594 lock_mode X insert intention waiting
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
 0: len 8; hex 73757072656d756d; asc supremum;;

*** WE ROLL BACK TRANSACTION (2)
  • 死锁分析

T1

T2

select * from user where name='tenmao' for update 记录不存在所以获取gap锁,模式是X

select * from user where name='tenmao' for update 记录不存在所以获取gap锁,模式是X(因为gap锁之间不冲突,所以可以获取)

insert into user(`name`) values('tenmao') 插入需要获取插入意向锁。因为与T2的gap锁冲突,需要等待

insert into user(`name`) values('tenmao') 插入需要获取插入意向锁。。因为与T1的gap锁冲突,需要等待。死锁!

死锁场景二

  • SQL语句
代码语言:javascript
复制
insert into user(`name`) values('tenmao');
  • 死锁分析

T1

T2

insert into user(`name`) values('tenmao') 第一阶段,需要判断duplicate key,所以获取S锁,类型是gap

insert into user(`name`) values('tenmao') 第一阶段,需要判断duplicate key,所以获取S锁,类型是gap

第二阶段,S锁升级为X锁。等待T2释放S锁

第二阶段,S锁升级为X锁。等待T2释放S锁(死锁)

以上过程,因为S锁升级为X锁的时间间隔很短,所以不是很好复现,一般在高并发的时候出现。不过可以用3个事务来复现:

T1

T2

T3

insert into user(`name`) values('tenmao'); 先获取S锁判断duplicate key,插入前升级为X锁

insert into user(`name`) values('tenmao'); 第一阶段,需要判断duplicate key,所以获取S锁,类型是gap,与T1的X锁冲突,等待

insert into user(`name`) values('tenmao'); 第一阶段,需要判断duplicate key,所以获取S锁,类型是gap,与T1的X锁冲突,等待

rollback

获取到S锁,类型是gap

获取到S锁,类型是gap

第二阶段,S锁升级为X锁。等待T3释放S锁(死锁)

第二阶段,S锁升级为X锁。等待T2释放S锁(死锁)

参考

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 表结构
  • 死锁场景一
  • 死锁场景二
  • 参考
相关产品与服务
云数据库 MySQL
腾讯云数据库 MySQL(TencentDB for MySQL)为用户提供安全可靠,性能卓越、易于维护的企业级云数据库服务。其具备6大企业级特性,包括企业级定制内核、企业级高可用、企业级高可靠、企业级安全、企业级扩展以及企业级智能运维。通过使用腾讯云数据库 MySQL,可实现分钟级别的数据库部署、弹性扩展以及全自动化的运维管理,不仅经济实惠,而且稳定可靠,易于运维。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档