MySQL 实战 45 讲
林晓斌
网名丁奇,前腾讯云数据库负责人
224874 人已学习
新⼈⾸单¥68
登录后,你可以任选4讲全文学习
课程目录
已完结/共 49 讲
实践篇 (37讲)
特别放送 (1讲)
结课测试 (1讲)
MySQL 实战 45 讲
15
15
1.0x
00:00/00:00
登录|注册

30 | 答疑文章(二):用动态的观点看加锁

间隙由右边的记录定义
加锁顺序要避免死锁
分析show engine innodb status输出的事务信息和死锁信息
加锁规则需要结合语句执行逻辑分析
并发执行可能导致锁等待
加锁范围:(5,10]、(10,15]、(15,20]、(20,25]、(25,supremum]
例子:update t set c = 5 where c = 1
分析锁等待信息
show engine innodb status命令输出的TRANSACTIONS部分
例子:delete from t where id=10
加锁顺序相反可能导致死锁
分析死锁现场信息
show engine innodb status命令输出的LATEST DETECTED DEADLOCK部分
并发执行可能导致死锁
加锁顺序:c=5、c=10、c=20
加锁范围:(0,5]、(5,10]、(10,15)、(15,20)、(20,25)
例子:select id from t where c in(5,20,10) lock in share mode
加锁动作发生在语句执行过程中,从索引上的数据结构开始分析
优化2:索引上的等值查询,向右遍历时id=15不满足条件,next-key lock退化为间隙锁(10,15)
加锁范围:(0,5]、(5,10]、(10,15)
例子:select * from t where id>9 and id<12 order by id desc for update
一个bug:唯一索引上的范围查询会访问到不满足条件的第一个值为止
优化2:索引上的等值查询,向右遍历时且最后一个值不满足等值条件的时候,next-key lock退化为间隙锁
优化1:索引上的等值查询,给唯一索引加锁的时候,next-key lock退化为行锁
原则2:查找过程中访问到的对象才会加锁
原则1:加锁的基本单位是next-key lock
小结
update的例子
怎么看锁等待?
怎么看死锁?
等值查询的过程
不等号条件里的等值查询
加锁规则
答疑文章(二):用动态的观点看加锁

该思维导图由 AI 生成,仅供参考

在第2021篇文章中,我和你介绍了 InnoDB 的间隙锁、next-key lock,以及加锁规则。在这两篇文章的评论区,出现了很多高质量的留言。我觉得通过分析这些问题,可以帮助你加深对加锁规则的理解。
所以,我就从中挑选了几个有代表性的问题,构成了今天这篇答疑文章的主题,即:用动态的观点看加锁。
为了方便你理解,我们再一起复习一下加锁规则。这个规则中,包含了两个“原则”、两个“优化”和一个“bug”:
原则 1:加锁的基本单位是 next-key lock。希望你还记得,next-key lock 是前开后闭区间。
原则 2:查找过程中访问到的对象才会加锁。
优化 1:索引上的等值查询,给唯一索引加锁的时候,next-key lock 退化为行锁。
优化 2:索引上的等值查询,向右遍历时且最后一个值不满足等值条件的时候,next-key lock 退化为间隙锁。
一个 bug:唯一索引上的范围查询会访问到不满足条件的第一个值为止。
接下来,我们的讨论还是基于下面这个表 t:
CREATE TABLE `t` (
`id` int(11) NOT NULL,
`c` int(11) DEFAULT NULL,
`d` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `c` (`c`)
) ENGINE=InnoDB;
insert into t values(0,0,0),(5,5,5),
(10,10,10),(15,15,15),(20,20,20),(25,25,25);

不等号条件里的等值查询

有同学对“等值查询”提出了疑问:等值查询和“遍历”有什么区别?为什么我们文章的例子里面,where 条件是不等号,这个过程里也有等值查询?
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入探讨了InnoDB的加锁规则,通过具体案例分析和读者提问,动态解析了加锁过程。文章首先回顾了加锁规则,包括next-key lock作为基本单位、访问对象才会加锁等内容。随后,通过查询案例分析了不等号条件中的等值查询和并发执行可能出现的死锁问题。文章还展示了通过执行show engine innodb status命令得到的死锁现场信息,并推导出了死锁的原因和解决方法。通过这些案例分析,读者可以深入了解InnoDB加锁规则的实际应用和可能遇到的并发问题,为他们在实际开发中避免类似问题提供了有益的参考。文章内容丰富,深入浅出,对于想深入了解MySQL原理的读者具有很高的参考价值。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《MySQL 实战 45 讲》
新⼈⾸单¥68
立即购买
登录 后留言

全部留言(96)

  • 最新
  • 精选
  • 令狐少侠
    置顶
    有个问题想确认下,在死锁日志里,lock_mode X waiting是间隙锁+行锁,lock_mode X locks rec but not gap这种加but not gap才是行锁? 老师你后面能说下group by的原理吗,我看目录里面没有

    作者回复: 对, 好问题 lock_mode X waiting表示next-key lock; lock_mode X locks rec but not gap是只有行锁; 还有一种 “locks gap before rec”,就是只有间隙锁;

    2019-01-22
    2
    93
  • Ryoma
    置顶
    删除数据,导致锁扩大的描述:“因此,我们就知道了,由于 delete 操作把 id=10 这一行删掉了,原来的两个间隙 (5,10)、(10,15)变成了一个 (5,15)。” 我觉得这个提到的(5, 10) 和 (10, 15)两个间隙会让人有点误解,实际上在删除之前间隙锁只有一个(10, 15),删除了数据之后,导致间隙锁左侧扩张成了5,间隙锁成为了(5, 15)。

    作者回复: 嗯 所以我这里特别小心地没有写“锁“这个字。 间隙 (5,10)、(10,15)是客观存在的。 你提得也很对,“锁”是执行过程中才加的,是一个动态的概念。 这个问题也能够让大家更了解我们标题的意思,置顶了哈 👍

    2019-01-22
    12
    157
  • IceGeek17
    老师,新年好,有几个问题: 问题一: 对于文中的第一个例子(不等号条件里的等值查询),当试图去找 “第一个id<12的值"的时候,用的还是从左往右的遍历(因为用到了优化2),也就是说,当去找第一个等值的时候(通过树搜索去定位记录的时候),即使order by desc,但用的还是向右遍历,当找到了第一个等值的时候(例子中的id=15),然后根据order by desc,再向左遍历。 是不是这么理解? 问题二: 对于第21讲的思考题, select * from t where c>=15 and c<=20 order by c desc lock in share mode, 老师已经给出了答案,我这里再详细理解一下: 先定位索引c上最右边c=20的行,所以第一个等值查询会扫描到c=25,然后通过优化2,next-key lock退化为间隙锁,则会加上间隙锁(20,25),紧接着再向左遍历,会加 next-key lock (15, 20], (10, 15], 因为要扫描到c=10才停下来,所以也会加next-key lock (5,10] 理解的是否正确? 问题三: 对于上面的问题二的sql,在索引c上,把(10,25)这段区间锁上就应该是完备的了,理论上(5,10]这段区间是否锁上对结果应该没有影响呀。 是不是说MySQL就是这么实现的,next-key lock前开后闭,因为扫到了c=10,所以会加next-key lock (5,10],这里MySQL的实现扩大了锁的区间范围,其实没有这个必要? 另外,如果不加next-key lock (5,10],是不是这里c=10还是应该要锁的,如果不锁可能被删除?

    作者回复: 1. 对的 2. 对的 3. “因为扫到了c=10,所以会加next-key lock (5,10]”, 对的。 第二个“如果”,实现上并不是这样的,所以没法回答😆

    2019-02-11
    8
    59
  • Jason_鹏
    最后一个update的例子,为没有加(0,5)的间隙呢?我理解应该是先拿c=5去b+树搜索,按照间隙索最右原则,应该会加(0,5]的间隙,然后c=5不满足大于5条件,根据优化2原则退化成(0,5)的间隙索,我是这样理解的

    作者回复: 根据c>5查到的第一个记录是c=10,因此不会加(0,5]这个next-key lock。 你提醒得对,我应该多说明这句, 我加到文稿中啦👍

    2019-01-22
    7
    40
  • 长杰
    老师,之前讲这个例子时,select * from t where c>=15 and c<=20 order by c desc in share mode; 最右边加的是 (20, 25)的间隙锁, 而这个例子select * from t where id>10 and id<=15 for update中,最右边加的是(15,20]的next-key锁, 这两个查询为何最后边一个加的gap锁,一个加的next-key锁,他们都是<=的等值范围查询,区别在哪里?

    作者回复: select * from t where c>=15 and c<=20 order by c desc in share mode; 这个语句是根据 c=20 来查数据的,所以加锁(20,25]的时候,可以使用优化2; select * from t where id>10 and id<=15 for update; 这里的id=20,是用“向右遍历”的方式得到的,没有优化,按照“以next-key lock”为加锁单位来执行

    2019-01-22
    12
    20
  • 老师好: select * from t where c>=15 and c<=20 order by c desc for update; 为什么这种c=20就是用来查数据的就不是向右遍历 select * from t where c>=15 and c<=20 这种就是向右遍历 怎么去判断合适是查找数据,何时又是遍历呢,是因为第一个有order by desc,然后反向向左遍历了吗?所以只需要[20,25)来判断已经是最后一个20就可以了是吧

    作者回复: 索引搜索就是 “找到第一个值,然后向左或向右遍历”, order by desc 就是要用最大的值来找第一个; order by就是要用做小的值来找第一个; “所以只需要[20,25)来判断已经是最后一个20就可以了是吧”, 你描述的意思是对的,但是在MySQL里面不建议写这样的前闭后开区间哈,容易造成误解。 可以描述为: “取第一个id=20后,向右遍历(25,25)这个间隙”^_^

    2019-01-22
    17
  • Long
    感觉这篇文章以及前面加锁的文章,提升了自己的认知。还有,谢谢老师讲解了日志的对应细节……还愿了

    作者回复: 😆 👍

    2019-01-28
    14
  • 长杰
    老师,select * from t where id>10 and id<=15 for update;这个语句持有的锁不应该是(5,10)(10,15](15,20)吗?

    作者回复: 不是哦,这里第一个id>10找到的是(10,15)这个gap,并没有加(5,10), 还有根据股则里面的“bug”,id=20也会被锁的,所以应该是(10,15](15,20]

    2019-01-21
    2
    13
  • 唯她命
    老师,update语句 mysql在执行过程中 ,都是先拆成 插入 和 删除的吗?不是直接修改?

    作者回复: 修改索引值都会修改位置的😆

    2019-04-03
    2
    10
  • hal
    非常谢谢老师,专栏质量非常高,祝老师身体健康万事如意,因为内容写的太好了……很激动👍👍👍👍👍

    作者回复: 🤝🤝🤝🤝🤝

    2019-06-01
    9
收起评论
显示
设置
留言
96
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部