Skip to content

类型

  • 表锁
  • 行锁

表锁

  • 会锁住整个表,粒度太大不推荐使用
sql
//表级别的共享锁,也就是读锁;
lock tables student read;
//表级别的独占锁,也就是写锁;
lock tables student write;
//解锁
unlock tables

行锁

  • 共享锁(S锁)
  • 独占锁(X锁)
sql
//对读取的记录加共享锁(S锁)
select ... lock in share mode;
//对读取的记录加独占锁(X锁)
select ... for update;

记录锁(Record Lock)

  • 记录锁也被称为行锁,顾名思义,它是针对数据库中的行记录进行的锁定。
sql
SELECT * FROM `user` WHERE `id`=1 FOR UPDATE;
  • 上面的SQL会在 id=1 的行记录上加上记录锁,以阻止其他事务插入,更新,删除这一行。

间隙锁(Gap Lock)

  • 间隙锁就是对间隙加锁,用于锁定索引范围之间的间隙,以避免其他事务在这个范围内插入新的数据。间隙锁是排它锁,阻止了其他事务在间隙中插入满足条件的值,间隙锁仅在可重复读隔离级别下才有效。

    事务A

sql
BEGIN;
SELECT * FROM `products` WHERE `product_id` BETWEEN 100 and 200 FOR UPDATE;

事务B

sql
BEGIN;
INSERT INTO `products` (`product_id`, `name`) VALUES (150, 'Product 150');

在这种情况下,事务A会在products表中product_id值在 100 和 200 之间的范围上设置间隙锁。因此,在事务A运行期间,其他事务无法在这个范围内插入新的数据,在事务B尝试插入product_id为150的记录时,由于该记录位于事务A锁定的间隙范围内,事务B将被阻塞,直到事务A释放间隙锁为止。

间隙锁触发条件

在可重复读(Repeatable Read)事务隔离级别下,以下情况会产生间隙锁:

  • 使用普通索引锁定:当一个事务使用普通索引进行条件查询时,MySQL会在满足条件的索引范围之间的间隙上生成间隙锁。
  • 使用多列唯一索引:如果一个表存在多列组成的唯一索引,并且事务对这些列进行条件查询时,MySQL会在满足条件的索引范围之间的间隙上生成间隙锁。
  • 使用唯一索引锁定多行记录:当一个事务使用唯一索引来锁定多行记录时,MySQL会在这些记录之间的间隙上生成间隙锁,以确保其他事务无法在这个范围内插入新的数据。

间隙锁加锁规则

  • 规则1:加锁的基本单位是 Next-Key Lock,左开右闭区间。
  • 规则2:查找过程中访问到的对象才会加锁。
  • 规则3:唯一索引上的范围查询会上锁到不满足条件的第一个值为止。
  • 规则4:唯一索引等值查询,并且记录存在,Next-Key Lock 退化为行锁。
  • 规则5:索引上的等值查询,会将距离最近的左边界和右边界作为锁定范围,如果索引不是唯一索引还会继续向右匹配,直到遇见第一个不满足条件的值,如果最后一个值不等于查询条件,Next-Key Lock 退化为间隙锁。

临键锁(Next-Key Lock)

  • 临键锁由记录锁和间隙锁组合而成,它在索引范围内的记录上加上记录锁,并在索引范围之间的间隙上加上间隙锁。这样可以避免幻读(Phantom Read)的问题,确保事务的隔离性。
  • 切记:间隙锁的区间是左开右开的,临键锁的区间是左开右闭的。