最近遇到一个由于唯一性索引 , 导致并发插入产生死锁的场景 , 在分析死锁产生的原因时 , 发现这一块还挺有意思的 , 涉及到MySQL中不少的知识点 , 特此总结记录一下 。
一、MySql常见的锁谈到mysql的锁 , 可以说的就比较多了 , 比如行锁、表锁、页锁、元数据锁等 , 当然我们这里没打算把所有的都细列出来 , 我们这里主要针对行锁、gap锁进行拓展 , 以方便分析第二节中 , 为什么并发插入同样的数据会产生死锁的问题
0. 锁分类
我们最常说的锁 , 可以区分为共享锁(S)和排它锁(X) , 在mysql的innodb引擎中 , 为了解决幻读问题 , 引入了gap锁以及next key lock;除此之外 , 还有一种意向锁的 , 比如插入意向锁
本文将主要介绍的以下几种锁
- 行锁(record lock): 请注意它是针对索引的锁(所以如果没有索引时 , 最终行锁就会导致整个表都会被锁住)
- 共享锁(S Lock): 也叫读锁 , 共享锁之间不会相互阻塞(顾名思义)
- 排它锁(X Lock): 也叫写锁 , 排它锁一次只能有一个session(或者说事务?)持有
- 间隙锁(gap lock): 针对索引之间的间隙
- Next-key锁(Next-key lock):可以简单理解为行锁 + 间隙锁
下面所有的都是基于mysql5.7.22 innodb引擎 , rr隔离级别进行说明
1.共享锁与排它锁
下表介绍我们的实际使用的sql中 , 是否会使用锁 , 以及会产生什么锁
共享锁与排他锁区分
文章插图
2. 行锁、表锁、gap锁、next-key锁区分
这几个的区分 , 主要就是看我们最终锁住的效果 , 比如
- 没有索引 , 加S/X锁最终都是锁整表 (为啥?因为锁是针对索引而言的)
- 根据主键/唯一键锁定确定的记录:行锁
- 普通索引或者范围查询:gap lock / next key lock
- 行锁针对确定的记录
- 间隙锁是两个确定记录之间的范围; next key lock则是除了间隙还包括确定的记录
看上面的两个说明 , 自然就想在实际的case中操刀分析一下 , 不同的sql会产生什么样的锁效果
- 针对表中一条确定的记录加X锁 , 是只有行锁嘛?
- 针对表中多条确定的记录加X锁 , 又会怎样?
- 针对表中一条不存在的记录加X锁 , 会有锁产生吗?如果是gap锁 , 那区间怎么定?
- 针对范围加X锁 , 产生的gap锁范围怎么确定呢?
其次不同的索引 , 我们需要分别进行测试(其实就是唯一索引与普通索引)
3.1 表准备
接下来针对上面的四种场景 , 设计我们的测试用例 , 首先我们准备三张表
- 无索引表 TN
- 唯一索引表 TU
- 普通索引表 TI
CREATE TABLE `tn` (`id` int(11) unsigned NOT NULL,`uid` int(11) unsigned NOT NULL) ENGINE=InnoDB;CREATE TABLE `tu` (`id` int(11) unsigned NOT NULL AUTO_INCREMENT,`uid` int(11) unsigned NOT NULL,PRIMARY KEY (`id`),UNIQUE KEY `u_uid` (`uid`)) ENGINE=InnoDB;CREATE TABLE `ti` (`id` int(11) unsigned NOT NULL AUTO_INCREMENT,`uid` int(11) unsigned NOT NULL,PRIMARY KEY (`id`),KEY `u_uid` (`uid`)) ENGINE=InnoDB;INSERT INTO `tn` (`id`, `uid`) VALUES (1, 10), (5, 20), (10, 30);INSERT INTO `tu` (`id`, `uid`) VALUES (1, 10), (5, 20), (10, 30);INSERT INTO `ti` (`id`, `uid`) VALUES (1, 10), (5, 20), (10, 30);
3.2 精确匹配即我们的sql可以精确命中某条记录时 , 锁的情况如下:
文章插图
请注意上面的结论 , 无索引时锁全表好理解 , 但是普通索引的TI表 , 居然还有一个[10, 30)的gap锁就有点超乎我们的想象了;
接下来我们验证一下
推荐阅读
- JS排序算法:冒泡、选择、插入、归并、快速、希尔、堆、计数
- 清朝男人为什么梳辫子 清朝男人辫子多久洗一次
- |钓一次鱼要用十几斤玉米?野钓翘嘴鱼窝料不在多,打窝节奏很关键
- 汽车刹车片多久换一次才是最安全
- 一次不经意的相遇,让我们?今天是我们相识的第100天
- 2.春种一粒粟?种一粒粟春种一粒粟
- Mybatis 批量插入万条数据
- 高并发服务遇Redis瓶颈引发的事故
- 一次难忘的滑雪经历?滑雪场的奇妙邂逅
- 最早出使西域为开辟丝绸之路做出贡献的是谁 张第一次出使西域的主要目的是什么