InnoDB为何在唯一索引唯一查询条件下使用间隙锁?
问题场景与解答
数据表结构
CREATE TABLE `bar` ( `id` int(11) NOT NULL, `age` int(11) NOT NULL, `value` int(11) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB
现有数据
id|age|value| --+---+-----+ 1| 1| 1| 5| 5| 5| 9| 9| 9|
操作流程
- 连接1执行:
start transaction; update bar set value = 0 where id = 8;
- 连接2执行:
start transaction; insert into bar(id,age,value) values(7,7,7);
此时连接2的插入操作被间隙锁阻塞,锁信息如下:
lock_id |lock_trx_id|lock_mode|lock_type|lock_table |lock_index|lock_space|lock_page|lock_rec|lock_data| -----------+-----------+---------+---------+-----------+----------+----------+---------+--------+---------+ 5218:85:3:4|5218 |X,GAP |RECORD |`bar`.`bar`|PRIMARY | 85| 3| 4|9 | 5217:85:3:4|5217 |X,GAP |RECORD |`bar`.`bar`|PRIMARY | 85| 3| 4|9 |
核心疑问
根据官方文档说明:
UPDATE ... WHERE ...会对搜索到的每条记录设置排他临键锁。但使用唯一索引查询唯一行的语句仅需索引记录锁
问:是否仅在找到并锁定记录时才使用索引记录锁,否则仍需使用临键锁?
是的,你的理解完全正确。
当使用唯一索引查询唯一行时,只有在找到匹配的记录时,InnoDB才会使用索引记录锁(Record Lock)——仅锁定该条具体的索引记录,不会额外添加间隙锁或临键锁。
但如果查询的唯一索引值不存在对应记录,InnoDB无法定位到具体行,此时会退化为添加间隙锁(GAP Lock)(临键锁本质是记录锁+间隙锁的组合),防止其他事务插入该间隙内的数据,避免幻读问题。
回到你的场景:连接1执行update bar set value = 0 where id = 8时,id作为主键(唯一索引)不存在对应记录,InnoDB会定位到id=5与id=9之间的间隙,并对该间隙添加X类型的间隙锁,这直接导致连接2插入id=7时被阻塞,与你看到的X,GAP锁信息完全吻合。
内容的提问来源于stack exchange,提问作者Tim
相关产品推荐
相关产品推荐

