介绍一下MySQL中的表锁、行锁、间隙锁,以及他们都在什么情况下会使用
表锁 (Table Lock)
1. 是什么:
表锁是锁住整张表,开销小,加锁快,但锁粒度大,发生锁冲突的概率最高,并发度最低。
2. 使用场景:
- MyISAM引擎:由于不支持事务和行锁,默认全用表锁。
- InnoDB中的DDL操作:执行
ALTER TABLE等修改表结构的语句时,会加表锁。 - 全表扫描的更新:如果一条
UPDATE或DELETE语句没有命中索引,InnoDB会锁住整张表(行锁升级为表锁,这是面试大坑!)。 - 备份场景:比如前面提到的
FLUSH TABLES WITH READ LOCK(FTWRL)(注意:这是一条sql命令关闭所有打开的表,同时对于所有数据库中的表都加一个读锁,直到显式地执行unlock tables,该操作常
常用于数据备份的时候。),就是加全局读锁。
行锁 (Row Lock)
1. 是什么:
锁住单行记录。开销大,加锁慢,会出现死锁,但锁粒度最小,并发度最高。InnoDB默认支持行锁。
2. 分类(基于模式):
- 共享锁(S锁 / 读锁):
SELECT ... LOCK IN SHARE MODE;允许其他事务读,阻止写。 - 排他锁(X锁 / 写锁):
SELECT ... FOR UPDATE;或UPDATE/DELETE语句。允许事务读写,阻止其他事务读写。
3. 记录锁(Record Lock):
行锁的典型实现就是记录锁,锁定的是索引记录本身(注意:是索引记录,不是数据行!)。
4. 使用场景:
- 高并发下的精确更新:如
UPDATE user SET age = 18 WHERE id = 10(id是主键或唯一索引)。 - 悲观锁的实现:通过在SQL中显式加
FOR UPDATE来保证并发安全。
5. 面试加分点:
“行锁的加锁是基于索引的,如果一条SQL走的是辅助索引,那么不仅会锁住辅助索引记录,还会回表锁住对应的主键索引记录。”
四、 间隙锁 (Gap Lock)
1. 是什么:
间隙锁锁定的是索引记录之间的“间隙”(开区间),或者第一条记录之前的间隙,或者最后一条记录之后的间隙。它不锁定记录本身。
2. 核心作用:
防止幻读。在“可重复读(RR)”隔离级别下,如果一个事务在范围内查询,另一个事务在这个范围内插入了新数据,为了避免前一个事务两次查询结果不一致(幻读),InnoDB引入了间隙锁,阻止其他事务在这个间隙内插入数据。
3. 特点:
- 只在 RR 隔离级别下生效(RC隔离级别下没有间隙锁)。
- 间隙锁之间不互斥:两个事务可以同时持有同一个间隙的锁。
- 与插入操作(Insert)互斥。
4. 组合武器:临键锁 (Next-Key Lock)
在RR级别下,InnoDB默认使用的是临键锁,它是记录锁 + 间隙锁的组合。锁定的是一个左开右闭的区间,例如 (5, 10]。
- 如果是唯一索引的等值查询,且记录存在,Next-Key Lock 会退化为记录锁。
- 如果是等值查询,但记录不存在,会退化为间隙锁。
5. 使用场景:
- RR隔离级别下的范围查询:如
SELECT * FROM user WHERE age > 10 FOR UPDATE;这会将(10, +∞)的间隙全部锁住,其他事务无法插入 age > 10 的数据。 - 等值查询不存在的记录:如
SELECT * FROM user WHERE id = 15 FOR UPDATE;如果 id=15 不存在,会锁住(10, 20)这个间隙。
浙公网安备 33010602011771号