加锁规则
间隙锁只有在可重复读的隔离级别下有效。
1. 两个原则
- 加锁的单位是 next-key lock,这个区间是前开后闭。
- 查找过程中访问的对象才会加锁。
2. 两个优化
- 在索引上的等值查询(where ... = ...),如果加锁的对象是唯一索引,则next-key lock的将会退化为行锁。
- 在索引上的等值查询,向右遍历的时候,如果最后一个值不满足条件的话,则next-key lock 会退化,变成间隙锁(前开后开区间)。
3. 一个Bug
唯一索引上的范围查询,会访问到第一个不满足条件的数据为止。
4. 举个例子
代码语言:javascript复制CREATE TABLE `t` (
`id` int(11) NOT NULL,
`c` int(11) DEFAULT NULL,
`d` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `c` (`c`)
) ENGINE=InnoDB;
insert into t values(0,0,0),(5,5,5),
(10,10,10),(15,15,15),(20,20,20),(25,25,25);
4.1 next-key 退化为行锁
- session A 查找id=10的时候,本来的加锁范围是(0,10],根据原则1退化为行锁加锁范围变成行锁id=10。
- session A向后查找的过程中的间隙锁为(10,15]
- 综合来看sessionA的加锁范围为[10,15]
- 因此 sessionB的insert into t values (8,8,8)不会锁住,而(13,13,13)会被锁住。
4.2 next-key 退化为间隙锁
- session A 本来的加锁范围是(5,10]
- 但是id=10是最后一个值,且不满足条件
- session A的加锁范围变成了(5,10), 所以session B 被阻塞,而session C没有阻塞。
4.3 一个bug
- session A锁住的范围其实是(10,20],因为唯一索引上的范围查询,会访问到第一个不满足条件的数据为止。
- 因此session B 和 session C会被锁住。
- 但是正确锁的范围是(10,15]