概述

InnoDB中行锁一共有3种,分别是:记录锁(Record lock)间隙锁Next-Key锁

Record锁是作用于单条行记录,而间隙锁Next-Key锁是一个范围锁,可锁定某个范围的行记录,它们是很相近的概念,可以说后者包含了前者,它们可以用来解决RR隔离级别下的幻读问题。

注意:如果检索条件不是索引的话会全表扫描,则是表锁,不是行锁

间隙锁

首先间隙锁是行锁,运行在RR隔离级别下。其次,它锁住的是一个范围,但不包括记录本身。

触发语句

RR隔离级别下的一个非表扫描的条件检索语句加上共享锁排它锁就触发了间隙锁(其实是触发的是Next-Key锁,后面解释)。

1
2
mysql> select * from users where age = 20 for update;
mysql> select * from users where age > 23 and age < 26 lock in share mode;

上面实例中的age字段是一个索引字段,确保检索操作走的是索引。

锁定范围

当检索条件是=时,锁定结果记录与上行和下行的间隙。

当检索条件是个范围时,就给这个范围锁定。

假设有张users表,ID为自增主键,age为索引字段。全部的数据如表单1。

表单1

age ID
10 100
23 101
14 102
20 107
20 108
26 120
16 123

我们将要演示语句走的是age辅助索引,又因为这个索引使用B树数据结构,索引中的排序是从小到大的或从大到小的,不是表单1看的那样,而是表单2那样。

表单2

age
10
14
16
20
20
23
26

等于条件检索

1
mysql> select * from users where age = 20 for update;

观看表单2,我们可以看到”20”与上行”10”的间隙是(16, 20),”20”与下行”23”的间隙是(20, 23),这2个区间将会被锁定。也就是你想插入一条age的值在这个区间的新记录,或者修改某已经存在的行的age值为这2个区间时,都将会被阻塞。

范围条件检索

1
mysql> select * from users where age > 23 and age < 26 for update;

如语句限制,age值范围为(23, 26)的记录的插入或修改都会被阻塞。

Next-Key锁

当启用触发加锁语句后,Next-Key锁是InnoDB默认加锁方式。

它是间隙锁记录锁的结合,它锁住的是一个范围,并且包括记录本身。

于是上面的”等于条件检索”演示的锁定范围就变成(16, 23)。

防止幻读

幻读:

幻读指的是一个事务在前后两次查询同一个范围的时候,后一次查询看到了前一次查询没有看到的行。

如何防止幻读?就是不允许其它事务插入或修改某些数据。

例如,某事务要获取年龄在(23, 26)之间的用户,为了防止幻读,也就是不允许其它事务插入年龄也在(23, 26)之间的用户,给查询语句加锁Next-Key锁就解决问题了。

1
mysql> select * from users where age > 23 and age < 26 for update;