- 记录锁:Record Locks
- 间隙锁:Gap Locks
- 临键锁:Next-key Locks
临键锁(Next-Key Locks)
定义
当 SQL 执行按照索引进行数据的检索时,查询条件为范围查找(between and、<、>等)并有数据命中,则此时 SQL 语句加上的锁为 Next-key locks,锁住索引的记录 + 区间(左开右闭)。
演示案例
演示之前,先看一下 t2 表的结构和数据内容。
临键锁(Next-key Locks):InnoDB 默认的行锁算法。
t2 表中的数据行有4条数据:1,4,7,10,InnoDB 引擎会将表中的数据划分为:(-∞, 1] (1, 4] (4, 7] (7, 10] (10, +∞),执行如下 SQL 语句:
-- 临键锁
-- 事务A执行
BEGIN;
SELECT * FROM t2 WHERE id>5 AND id<9 FOR UPDATE;
ROLLBACK
-- 事务B执行
BEGIN;
SELECT * FROM t2 WHERE id=4 FOR UPDATE; -- 可以执行
SELECT * FROM t2 WHERE id=7 FOR UPDATE; -- 锁住
SELECT * FROM t2 WHERE id=10 FOR UPDATE; -- 锁住
INSERT INTO `t2` (`id`, `name`) VALUES (9, '9'); -- 锁住
SELECT * FROM t2 WHERE id>5 AND id<9 FOR UPDATE;
这条查询语句命中了7这条数据,它会锁住 (4, 7] 这个区间,同时还会锁住下一个区间 (7, 10]。
为什么 InnoDB 选择临键锁作为行锁的默认算法?
防止幻读。当我们把下一个区间也锁住的时候,这个时候我们要新增数据,就会被锁住,这样就可以防止幻读。
间隙锁(Gap Locks)
定义
当 SQL 执行按照索引进行数据的检索时,查询条件的数据不存在,这时 SQL 语句加上的锁即为 Gap locks,锁住数据不存在的区间(左开右开)
Gap 只在 RR 事务隔离级别存在。因为幻读问题是在 RR 事务通过临键锁和 MVCC 解决的,而临键锁=间隙锁+记录锁,所以间隙锁只在 RR 事务隔离级别存在。
演示案例
-- 间隙锁
-- 事务A执行
BEGIN;
SELECT * FROM t2 WHERE id>4 AND id <6 FOR UPDATE;
-- 或者
SELECT * FROM t2 WHERE id=6 FOR UPDATE;
ROLLBACK;
-- 事务B执行
INSERT INTO `t2` (`id`, `name`) VALUES (5, '5');
INSERT INTO `t2` (`id`, `name`) VALUES (6, '6');
SELECT * FROM t2 WHERE id>4 AND id <6 FOR UPDATE;
这条查询语句不能命中数据,它会锁住 (4, 7] 这个区间。
记录锁(Record Locks)
定义
当 SQL 执行按照唯一性(Primary key、Unique key)索引进行数据的检索时,查询条件等值匹配且查询的数据是存在,这时 SQL 语句加上的锁即为记录锁 Record Locks,锁住具体的索引项。
演示案例
-- 记录锁
-- 事务A执行
BEGIN;
SELECT * FROM t2 WHERE id=4 FOR UPDATE;
ROLLBACK;
-- 事务B执行
SELECT * FROM t2 WHERE id=7 FOR UPDATE;
SELECT * FROM t2 WHERE id=4 FOR UPDATE;
事务A执行 SELECT * FROM t2 WHERE id=4 FOR UPDATE;
把 id=4 的数据行锁住。
当 SQL 执行按照普通索引进行数据的检索时,查询条件等值匹配且查询的数据是存在,这时 SQL 语句锁住数据存在区间(左开右开)
作者:殷建卫 链接:https://www.yuque.com/yinjianwei/vyrvkf/maliph 来源:殷建卫 - 架构笔记 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。