[面试题] 介绍下 InnoDB 的锁机制?
📖 版块 A:知识讲解版 (温故知新)
InnoDB 的锁机制是其支持高并发、 ACID 特性的核心保障。可以从以下三个维度进行拆解:
-
按锁的粒度分类:
- 行级锁 (Row Locks): 锁定具体的索引记录。开销大,但并发度最高。
- 表级锁 (Table Locks): 锁定整张表。开销小,并发度低。InnoDB 虽然支持表锁,但主要使用意向锁(IS/IX)来辅助处理行锁与表锁的冲突。
-
按锁的兼容性分类:
- 共享锁 (S 锁): 又称读锁,允许其他事务也加读锁,但禁止加写锁。
- 排他锁 (X 锁): 又称写锁,禁止其他事务加任何锁(包括 S 锁和 X 锁)。
-
按锁的算法分类(最核心):
- 记录锁 (Record Locks): 仅锁定索引记录本身。
- 间隙锁 (Gap Locks): 锁定索引记录之间的间隙,不包括记录本身。目的是防止幻读。
- 临键锁 (Next-Key Locks): 记录锁 + 间隙锁的组合,锁定一个范围并包括记录本身。是 InnoDB 在可重复读 (RR) 隔离级别下的默认锁算法。
- 意向锁 (Intention Locks): 表级锁,表示事务准备在行级加锁。IS(意向读)和 IX(意向写)的主要作用是提高加表锁时的冲突检测效率。
-
死锁检测:
- InnoDB 自动检测死锁循环,并会回滚 undo log 量最小的事务。
🎤 版块 B:面试实战版 (高手逐字稿)
Q:介绍下 InnoDB 的锁机制?
💬 高手逐字稿:
关于 InnoDB 的锁机制,我认为可以从“锁的粒度”、“兼容性”以及“锁算法”三个维度来系统理解。
首先,在粒度上,InnoDB 最显著的特点是支持行级锁。虽然它也有表级的意向锁(IS/IX),但意向锁的设计初衷不是为了阻塞,而是为了在事务申请表锁时,能快速判断表内是否有行被锁定,从而避免全表扫描,这是一种典型的“以空间换时间”的优化思路。
其次,在算法实现上,这是区分高手的地方。InnoDB 的行锁并不是直接锁在物理记录上的,而是锁在索引上的。它有三种算法:第一种是 Record Lock,只锁单行记录;第二种是 Gap Lock 间隙锁,锁定索引之间的区间,但不含记录本身;第三种是 Next-Key Lock,也就是前两者的结合。
这里有个关键点:在 RR(可重复读)隔离级别下,InnoDB 默认使用 Next-Key Lock。它通过锁定记录及其前后的间隙,配合 MVCC 机制,成功解决了“幻读”问题,这使得 InnoDB 的 RR 级别在安全性上几乎接近了 Serializable(串行化),但性能要好得多。
【高手自问自答】:这里有一个容易被忽略的边界细节:如果我的查询语句没有命中索引,会发生什么?如果是通过非索引字段进行更新,由于 InnoDB 的锁是基于索引的,在这种情况下,MySQL 无法实现精准的行锁定,会导致“锁升级”。虽然逻辑上它还是行锁,但它会给主键索引上的所有记录都加上锁,这在表现上就相当于锁住了整张表。这也是为什么我们在生产环境写 SQL 时,强调 Update 和 Delete 的谓词必须包含索引,否则会引发严重的并发崩溃。
最后,InnoDB 还有自动死锁检测机制。当发生死锁循环时,它会通过 wait-for graph 算法检测到,并主动回滚事务开销最小的那个,保证系统的整体可用性。