InsertIntentionLock,中文也叫InsertIntentionLock。这也算是对我们之前讲的GapLock的一个补充。关于GapLock,如果还有朋友不明白,可以参考:recordlock,gaplock和Next-KeyLocks。1、为什么要插入意向锁?我们之前已经有了GapLock。GapLock一定程度上可以帮助我们解决幻读的问题,但是前面那个好像有点问题。假设我有一个这样的表:CREATETABLE`user`(`id`int(11)unsignedNOTNULLAUTO_INCREMENT,`username`varchar(255)COLLATEutf8mb4_unicode_ciDEFAULTNULL,`age`int(11)NOTNULL,PRIMARYKEY(`id`),KEY`age`(`age`))ENGINE=InnoDBAUTO_INCREMENT=10DEFAULTCHARSET=utf8mb4COLLATE=utf8mb4_unicode_ci;id为主键自增;age是一个普通的索引,现在表中有如下数据:假设我要执行如下insertSQL:begin;insertintouser(username,age)values('wangwu',95);请注意,此SQL已执行,但事务尚未提交。根据我们之前学习的关于GapLock的知识,GapLock的范围是(89,99),也就是说这个范围内的age是不能插入的。如果是这样,小伙伴们会发现数据插入效率太低,容易出现锁冲突,那怎么办呢?我们今天要介绍的插入意向锁就是用来解决这个问题的。2、什么是插入意向锁?我们看一下MySQL官网的介绍:插入意向锁是一种在行插入之前通过INSERT操作设置的间隙锁。这个锁表示插入的意图,这样插入到同一个索引间隙中的多个事务如果没有插入到间隙中的相同位置,则不需要相互等待。假设有值为4和7的索引记录,分别尝试插入值为5和6的事务,在获得排他锁之前,分别用插入意向锁锁定4和7之间的间隙插入的行,但不要互相阻塞,因为这些行是不冲突的。在INSERT操作之前设置的间隙锁。插入意向锁代表一种插入意向,即当多个不同的事务同时向同一个索引的同一个间隙插入数据时,它们不需要互相等待。即不会阻塞(如果单纯按照前面的间隙锁理论,必须等待一个间隙锁释放后,下一个事务才能往同一个间隙插入数据)。假设有值为4和7的索引记录,现在有两个事务分别尝试插入值为5和6的记录。在获取插入行的排他锁之前,每个事务使用4到7之间的插入意向锁,但是两个事务不会互相阻塞,因为行不冲突。这是插入意图锁。3、各位同修注意了,之前宋哥跟大家讲过GapLock,说这是可重复读(REPEATABLEREAD)隔离级别下的独特产物,所以现在InsertIntentionLock当然是一种特殊的GapLock同样在可重复读隔离级别下生效。下面我们通过两个简单的案例来演示意向锁的插入。3.1案例一我们的表结构和数据与第一节一致。首先,我们在sessionA中执行如下代码:现在sessionA中的事务没有提交。接下来,我们同样在sessionB中进行insert操作:我们发现sessionB也可以正常执行,不会阻塞。这说明这两个插入意向锁是兼容的,可以共存。3.2案例2让我们来看另一个不兼容的例子。首先,在sessionA中,执行如下SQL查询年龄大于80的记录,并加排他锁:接下来,在sessionB中,执行如下代码,插入一行数据:朋友们,你可以看到这个操作将被阻止!阻塞的原因是插入意向锁和排他锁是互斥的。利用阻塞情况,在sessionC中,我们使用上一篇文章中使用的showengineinnodbstatus\G命令查看锁定情况,重点关注TRANSACTION节点:在输出内容中,红色方框所在的地方被选中清楚地表明了插入意向锁的存在。4.总结总结一下:插入意向锁虽然名字里有意向二字,但实际上是一种特殊的间隙锁。插入意向锁之间没有互斥。在意向锁和排它锁之间插入互斥。好了,有什么问题欢迎留言讨论。
