间隙锁(GapLock)是Innodb为解决可重复读提交下的幻读问题而引入的一种锁机制(以下所有案例均不特别强调使用可重复读隔离级别)幻读存在,因为新的或更新操作。这时候如果进行范围查询(锁查询),就会出现不一致的情况。这时候使用不同的行锁就没有办法满足要求了。需要对一定范围内的数据进行锁定,间隙锁就是为了解决这类问题。在可重复读隔离级别下,数据库通过行锁和间隙锁(next-keylock)的组合来实现。加锁规则有以下几个特点,我们将在下面的案例中一一说明:1、加锁的基本单位是(next-keylock),即先开后关,后关的原则。2.间歇访问的对象会加锁3.等价查询索引--当加锁唯一索引时,next-key锁升级为行锁4.等价查询索引--当最后一个值不存在时向右遍历时满足查询要求,next-key锁退化为间隙锁5.唯一索引上的范围查询会访问第一个不满足条件的值。为了解决幻读问题,case数据中的上述数据在更新时不仅对上述5条数据加了行锁,还为中间值范围加了6个间隙锁,(-∞,5](5,10](10,15](15,20](20,25](25,+supernum](其中supernum是数据库维护的最大值。为了保证间隙锁左开右闭。)案例一:间隙锁简单案例当有如下事务A和事务B时,事务A会对数据库表加(10,15]区间锁,当插入id=12的数据时,会被锁住,因为区间锁(10,15],无法执行。情况2:间隙锁死锁问题不同于写锁互斥的原理,间隙锁之间是不互斥的。如果一个事务A获取了之间的间隙锁(5,10],另外一个事务B也可以获得(5,10)之间的间隙锁。这时候就可能会出现A死锁问题发生,如以下情况。事务A获取了(5,10]之间的间隙锁,不允许其他DDL操作。在事务提交释放间隙锁之前,事务B也获取了间隙锁(5,10)。此时,两个事务处于死锁状态情况3:等价查询——唯一索引1,加锁范围为(5,10]范围锁2,由于数据是等价查询,表中最后一条数据id=10不满足id=7的查询要求,所以id=10的行级锁退化为间隙锁,(5,10)3。因此,在事务B中,id=8会被加锁,而id=10不会case4:等值查询—普通索引1锁定范围为(0,5],(5,10]rangelock2.由于c为普通索引,根据原则4,查找5后,继续向后遍历,直到达到10就放弃,所以锁定范围为(5,10]3。由于查询是等值查询,最后一个值不满足查询要求,则gap锁退化为(5,10)4。因为加锁是针对普通索引C加锁的,而因为覆盖了索引,所以主键没有加锁,所以事务B正常执行。5、因为锁定范围(5,10),事务C的执行被阻塞。6.需要注意的是,共享模式下的lock是因为覆盖索引不锁主键索引。如果使用forupdate程序,你会认为后面会进行更新操作,所以主键索引会被锁在一起。案例5:范围查询——唯一索引next-keylock根据原则5增加范围锁(5,10],唯一索引的范围查询会去到第一个不合规的值位置,所以加(10,15]因为等价查询有id=10根据原则3,间隙锁升级为行锁,所以剩下的锁[10,15]因为查询不是等价查询,所以[10,15]不会退化为[10,15),所以事务B(13,13,13)被阻塞,事务C被阻塞情况6:范围查询——普通索引next-keylock增加范围锁(5,10),(10,15]因为c是非唯一索引,所以(5,10]不会退化为10,因为查询不是等价查询,所以[10,15]不会退化为[10,15)因此,事务B和事务C都被阻塞案例7:在常见的索引等价问题上的数据中添加一行(30,10,30),使得数据库中有两条c=10的记录next-keylock增加范围锁定(5,10],(10,15]因为是等价查询,所以退化为(5,10],(10,15),所以事务B被阻塞,事务C执行成功锁定范围Case8如下图:普通index-equivalentLimit问题根据上述情况8修改,delete增加limit操作2的操作知道数据锁值加2,所以加锁(5,10]后发现已经有2条数据了,所以没有向后匹配加锁,所以事务B执行成功,并加锁范围如下作者:小亮__链接:https://www.jianshu.com/p/32904ee07e56来源:简书
