我敢打赌!这道关于MySQL中update加锁的问题,大部分人都答不出来

41 篇文章 0 订阅
26 篇文章 0 订阅

周末的时候,一个读者问了我一个很有意思的问题,是关于 MySQL 中 update 加锁的问题。

他用下面这张数据库表,做了个 MySQL 实验的时候。

在这里插入图片描述

发现事务 B 的 update 不会阻塞,而事务 C 的 update 会阻塞,都是对 id = 10 这条记录进行 update, 为什么一个会阻塞,一个不会阻塞?

在这里插入图片描述

首先,我们先来分析下,事务 A 这条 SQL 加了什么锁。

// 事务 A 
select * from t_person where id < 10 for update;

我直接说结论,事务 A 加了这三个行级锁:

1、在 id 为 1 的主键索引上,加了 X 型的 next-key 锁,范围是 (-∞,1]。意味着,其他事务无法对 id = 1
的记录进行删除和更新操作,同时无法插入 id 小于 1 的新记录。 2、在 id 为 5 的主键索引上,加了 X 型的 next-key
锁,范围是 (1, 5]。意味着,其他事务无法对 id = 5 的记录进行删除和更新操作,同时无法插入 id 为 2、3、4 的新记录。
3、在 id 为 10 的主键索引上,加了 X 型的间隙锁,范围是 (5, 10)。意味着,其他事务无法插入 id 为 6、7、8、9
的新纪录。

PS:如果你不清楚什么是 MySQL 这些行级锁(记录锁、间隙锁、next-key 锁),以及不清楚行级锁的加锁规则,强烈建议先看我之前写的这篇:MySQL 是怎么加行级锁的?,看完后,你回头看我这篇文章,就会有感觉的了。

事务 B 的 update 语句为什么不会阻塞?

事务 B 的 update 语句是对 id = 10 的行记录的 name 字段进行更新。

// 事务 B
update t_person set name = "小林" where id = 10;

事务 B 会在 id = 10 的主键索引上加 X 型记录锁,仅锁住这一行。因为当我们用唯一索引进行等值查询的时候,查询的记录是「存在」的,在索引树上定位到这一条记录后,该记录的索引中的 next-key 锁会退化成「记录锁」。

事务 A 并没有对 id = 10 的主键索引上加 X 型记录锁,而是对 id = 10 的主键索引上加 X 型间隙锁。间隙锁和记录锁之间是没有互斥关系的,所以事务 B 的 update 语句不会阻塞。

事务 C 的 update 语句为什么会阻塞?

事务 C 的 update 语句是将 id = 10 的行记录的 id 更新为 2。

// 事务 C
update t_person set id = 2 where id = 10;

这条 update 很特殊,特殊之处在于更新了主键索引。你以为它只是一个更新操作,实际上它在背后执行了两个操作:

操作 1:delete from t_person where id = 10;
操作 2:insert into t_person (2, 陈某, 30, 广州市海珠区);

也就是先删除 id = 10 的记录,然后再插入 id = 2 的新纪录。

为什么当 update 语句更新了索引值,会被拆分成删除和插入操作?

要回答这个问题,我们先要清楚 B+ 树的特点。

Innodb(MySQL 存储引擎)在实现索引的时候,采用的数据结构是 B+ 树。B+ 树是基于二分查找树演变过来的,所以 B+ 树在存储索引的时候,是按顺序存储的,因为这样才能利用二分查找快速检索到索引。

现在有一颗这样的 B+ 树,可以看到叶子节点的索引值是从小到大的顺序。

在这里插入图片描述

假设这时候需要将索引值为 25 更新为 3,如果直接索引值为 25 的位置上,将值改为 3 的话。

在这里插入图片描述

这时候你就会发现这棵 B+ 树不满足顺序性了!

所以更新索引的值,不能只是修改一个索引值就完事,而是还要保证更新后的索引值能继续满足 B+ 树的顺序性。

解决的方法就是,先删除索引值为 25 的节点,再插入索引值为 3 的节点,这样,这颗 B+ 树才能满足顺序性。

在这里插入图片描述

事务 C 的 update 语句具体阻塞在哪个「操作」?

现在我们知道,事务 C 的 update 特殊语句背后执行了两个操作,分别是删除和插入操作,那具体是阻塞在哪个「操作 」?

「操作 1 」是删除 id = 10 的记录,事务 C 是会在 id = 10 的主键索引上加 X 型记录锁,而事务 A 并没有对 id = 10 的主键索引上加 X 型记录锁,而是对 id = 10 的主键索引上加 X 型间隙锁。间隙锁和记录锁之间是没有互斥关系的,所以「操作 1 」不会阻塞。

根据排除法,既然 「操作 1 」不会阻塞,那事务 C 的 update 语句阻塞的原因就是因为 「操作 2」发生了阻塞。

为什么「操作2」会发生阻塞呢?

我们先要知道,插入操作什么时候会发生阻塞:插入语句在插入一条新记录之前,需要先定位到该记录在 B+树的位置,如果插入的位置的下一条记录的索引上有间隙锁,此时会生成一个插入意向锁,然后锁的状态设置为等待状态,现象就是插入语句会被阻塞。

「操作 2」插入的是 id = 2 的新记录,在主键索引的 B+树定位到插入的位置如下图。

在这里插入图片描述

插入位置的下一条记录是 id = 5 的记录,而事务 A 在 id 为 5 的主键索引上已经加了 X 型的 next-key 锁,这里面包含了间隙锁。所以「操作 2」的插入操作会发生阻塞,这就是事务 C 的 update 语句阻塞的原因。

从这我们也可以知道间隙锁的作用,就是阻止其他事务在间隙锁的范围内插入新记录,从而避免可重复读隔离级别下幻读的现象。

我们也可以通过 select * from performance_schema.data_locks\G; 这条语句,查看事务 C 在加什么锁的时候导致阻塞。

在这里插入图片描述

从上面的输出信息,可以看到事务 C 在加「插入意向锁」的时候,发生了阻塞。

插入意向锁是插入操作才会有的锁,而事务 C 只是执行 update 语句,却出现了插入意向锁,从这里也可以证明,事务 C 这条特殊的 update 语句运行的时候,被拆分成了两个操作,一个是删除,另一个是插入。

总之,如果 update 语句更新的是普通字段的值,就会对发生更新的记录加 X 型记录锁。

但是,如果 update 语句更新的是索引的值,那么在运行的时候会被拆分成删除和插入操作,这时候分析锁的时候,要从这两个操作的角度去分析。

(文章转载微信公众号:小林coding)

为了让开发者使用更简单高效的SQL开发工具,经过三年打磨,麦聪软件推出一款纯Web版多数据库管理和开发工具——SQL Studio

相比传统客户端SQL开发工具,SQL Studio工具:
1、无需安装一键启用;
2、支持团队在线协作开发和统一管理;
3、坚持100%自主研发;
4、支持当前主流数据库,同时全力支持达梦、人大金仓等国产数据库;
5、数千万行数据秒级导出以及创建数万张表,而系统不会出现卡死或闪退的情况。

在这里插入图片描述

目前,SQL Studio面向个人用户免费下载使用,欢迎到麦聪软件官网免费下载实测。

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Santo兴奋地来到他所赢得的大客厅。他站在门口,眼前呈现的是一片宽敞明亮的空间。客厅的装饰非常奢华,墙上挂着精美的画作,室内摆放着豪华的家具,整个氛围散发着高雅与舒适。 Santo迈步走进客厅,他的脚步声回荡在空旷的房间里,他不禁感叹起这个房子的优越性。客厅央摆放着一张巨大的沙发,看起来非常舒适。他四处张望,发现墙角还摆放着一台高清电视和音响系统,随便按一下遥控器就可享受到优质的娱乐体验。 Santo继续探索客厅,他发现一面挂着大镜子的墙壁。他走近镜子,看到自己的倒影。那一刻,他感觉自己仿佛成了一个时尚而成功的人。他决定将这个客厅打造成一个独特的空间,可以展示他的品味和个性。 在客厅的一侧,有一扇通向阳台的玻璃门。Santo走向阳台,眺望远处。蓝天,白云,繁忙的城市街道,这一切都尽收眼底。他知道,在这里,他可以享受到独立的自由和美好的生活。 思绪回到现实,Santo看着眼前的这个大客厅,感受到了满满的幸福和自豪。他决心好好利用这个空间,打造一个舒适温馨的家居环境,邀请朋友们来共度美好时光。 总的来说,Santo对他赢得的大客厅感到兴奋和欣喜。他对于这个空间的规划和利用充满了无限的想象力和期待。在这个客厅里,他将创造出一个独特的居住环境,为他的生活增添更多的快乐和满足感。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值