MySQL 是怎么加行级锁的?为什么一会是 next-key 锁,一会是间隙锁,一会又是记录锁?( 五 )


  • 在 id = 20 这条记录的主键索引上,加了范围为 (15, 20] 的 next-key 锁,意味着其他事务即无法更新或者删除 id = 20 的记录,同时无法插入 id 值为 16、17、18、19 的这一些新记录 。
  • 在特殊记录( supremum pseudo-record)的主键索引上,加了范围为 (20, +∞] 的 next-key 锁,意味着其他事务无法插入 id 值大于 20 的这一些新记录 。
实验二:针对「大于等于」的范围查询的情况 。
假设事务 A 执行了这条范围查询语句:
mysql> begin;Query OK, 0 rows affected (0.00 sec)mysql> select * from user where id >= 15 for update;+----+-----------+-----+| id | name      | age |+----+-----------+-----+| 15 | 乌索普    |  20 || 20 | 香克斯    |  39 |+----+-----------+-----+2 rows in set (0.00 sec)事务 A 加锁变化过程如下:
  1. 最开始要找的第一行是 id = 15,由于查询该记录是一个等值查询(等于 15),所以该主键索引的 next-key 锁会退化成记录锁,也就是仅锁住 id = 15 这一行记录 。
  2. 由于是范围查找,就会继续往后找存在的记录,扫描到的第二行是 id = 20,于是对该主键索引加的是范围为 (15, 20] 的 next-key 锁;
  3. 接着扫描到第三行的时候,扫描到了特殊记录( supremum pseudo-record),于是对该主键索引加的是范围为 (20, +∞] 的 next-key 锁 。
  4. 停止扫描 。
可以得知,事务 A 在主键索引上加了三个 X 型 的锁,分别是:
MySQL 是怎么加行级锁的?为什么一会是 next-key 锁,一会是间隙锁,一会又是记录锁?

文章插图
  • 在 id = 15 这条记录的主键索引上,加了记录锁,范围是 id = 15 这一行记录;意味着其他事务无法更新或者删除 id = 15 的这一条记录;
  • 在 id = 20 这条记录的主键索引上,加了 next-key 锁,范围是 (15, 20]。意味着其他事务即无法更新或者删除 id = 20 的记录,同时无法插入 id 值为 16、17、18、19 的这一些新记录 。
  • 在特殊记录( supremum pseudo-record)的主键索引上,加了 next-key 锁,范围是 (20, +∞]。意味着其他事务无法插入 id 值大于 20 的这一些新记录 。
我们也可以通过 select * from performance_schema.data_locks\G; 这条语句来看看事务 A 加了什么锁 。
输出结果如下,我这里只截取了行级锁的内容 。
MySQL 是怎么加行级锁的?为什么一会是 next-key 锁,一会是间隙锁,一会又是记录锁?

文章插图
通过前面这个实验,我们证明了:
  • 针对「大于等于」条件的唯一索引范围查询的情况下,如果条件值的记录存在于表中,那么由于查询该条件值的记录是包含一个等值查询的操作,所以该记录的索引中的 next-key 锁会退化成记录锁 。
2、针对「小于或者小于等于」的范围查询
实验一:针对「小于」的范围查询时,查询条件值的记录「不存在」表中的情况 。
假设事务 A 执行了这条范围查询语句,注意查询条件值的记录(id 为 6)并不存在于表中 。
mysql> begin;Query OK, 0 rows affected (0.00 sec)mysql> select * from user where id < 6 for update;+----+--------+-----+| id | name   | age |+----+--------+-----+|  1 | 路飞   |  19 ||  5 | 索隆   |  21 |+----+--------+-----+3 rows in set (0.00 sec)

经验总结扩展阅读