1. 行锁什么时候加上?

在 MySQL 的 InnoDB 引擎中,行锁是在事务执行过程中根据需要加上的,但并不是立即释放,
而是等到事务结束时才释放,这符合两阶段锁协议。具体来说,以下操作会触发行锁:

显式加锁:使用 SELECT ... FOR UPDATE 或 SELECT ... LOCK IN SHARE MODE 语句时,会对查询的行加锁。

隐式加锁:在执行 UPDATE 或 DELETE 操作时,InnoDB 会自动对操作的行加独占锁(X 型锁)。

索引条件与锁的关系:
普通 SELECT:不会加锁,无论是否使用索引。
SELECT ... FOR UPDATE 或 SELECT ... LOCK IN SHARE MODE:
如果查询条件使用了索引(包括主键或唯一索引),会加行锁。
如果查询条件没有使用索引,会加表锁。
因此,普通 SELECT 语句不会因为是否触发索引而加锁,只有在使用 FOR UPDATE 或 LOCK IN SHARE MODE 时,
索引的使用才会影响加锁的类型。

2. 索引与行锁的关系

InnoDB 的行锁是加在索引上的,这意味着:

主键索引:对主键或唯一索引加锁时,行锁会直接加在对应的索引记录上。
普通索引:对普通索引加锁时,行锁会加在索引项上,同时可能触发间隙锁或临键锁。
无索引:如果查询条件没有使用索引,InnoDB 会退化为表锁,锁住整个表。

3. 常见面试题

Q1: 什么是行锁、间隙锁和临键锁?

行锁(Record Lock):锁定单行记录,通常用于主键或唯一索引。
间隙锁(Gap Lock):锁定一个索引区间,防止其他事务在区间内插入数据,常用于普通索引或范围查询。
临键锁(Next-Key Lock):行锁和间隙锁的组合,锁定一个左开右闭的区间,用于解决幻读问题。

Q2: 什么时候会加间隙锁?

在基于普通索引或唯一索引的范围查询中,InnoDB 会自动加间隙锁。
例如,SELECT * FROM test WHERE id BETWEEN 5 AND 7 FOR UPDATE; 会锁定 (5, 7) 区间。

Q3: 如何避免表锁?

确保查询条件使用索引,否则 InnoDB 会退化为表锁。可以通过 EXPLAIN 分析查询是否使用了索引。

Q4: 什么是两阶段锁协议?

两阶段锁协议是指事务在执行过程中逐步加锁,但在事务提交或回滚时才统一释放锁。
这种机制确保了事务的隔离性和一致性。

Q5: 如何查看当前事务加的锁?

在 MySQL 8.0 及以上版本,可以通过 SELECT * FROM performance_schema.data_locks\G; 
查看 InnoDB 为事务加的锁。

4. 总结

MySQL 的行锁机制是 InnoDB 引擎实现事务隔离性的重要手段。
理解行锁、间隙锁和临键锁的区别,以及索引在加锁中的作用,
是优化数据库性能和解决并发问题的关键。

高旭
40 声望3 粉丝