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

事务 A 加锁变化过程如下:

  1. 最开始要找的第一行是 id = 20 , 由于查询该记录不是一个等值查询(不是大于等于条件查询),所以对该主键索引加的是范围为 (15, 20] 的 next-key 锁;
  2. 由于是范围查找,就会继续往后找存在的记录,虽然我们看见表中最后一条记录是 id = 20 的记录,但是实际在 Innodb 存储引擎中,会用一个特殊的记录来标识最后一条记录,该特殊的记录的名字叫 supremum pseudo-record,所以扫描第二行的时候 , 也就扫描到了这个特殊记录的时候,会对该主键索引加的是范围为 (20, +∞] 的 next-key 锁 。
  3. 停止扫描 。
可以得知,事务 A 在主键索引上加了两个 X 型 的 next-key 锁:
MySQL 是怎么加行级锁的?为什么一会是 next-key 锁,一会是间隙锁,一会又是记录锁?

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

文章插图
从上图中的分析中,也可以得到事务 A 在主键索引上加了两个 X 型 的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 锁,一会是间隙锁,一会又是记录锁?

文章插图
通过前面这个实验,我们证明了: