(相关资料图)
Insert Intention Lock,中文我们也称之为插入意向锁。
这个可以算是对我们之前所讲的 Gap Lock 的一个补充,关于 Gap Lock,如果还有小伙伴不懂,可以参考:记录锁、间隙锁与 Next-Key Locks。
1. 为什么需要插入意向锁
我们之前已经有 Gap Lock 了,Gap Lock 可以帮我们在一定程度上解决幻读问题,但是,之前的似乎有点问题。
假设我有如下一张表:
CREATE TABLE `user` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `username` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, `age` int(11) NOT NULL, PRIMARY KEY (`id`), KEY `age` (`age`)) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
登录后复制
id 是主键自增;age 是一个普通索引,现在表中有如下数据:
假设我想执行如下的插入 SQL:
begin;insert into user(username,age) values("wangwu",95);
登录后复制
注意,这个 SQL 执行了但是事务还没有提交。
按照我们之前学习的关于 Gap Lock 的知识分析一下,此时间隙锁的范围是 (89,99),意思是这个范围的 age 都不可以插入。
如果是这样的话,小伙伴们会发现数据插入的效率可就太低了,很容易发生锁冲突,那么怎么办?
我们今天要介绍的插入意向锁就是用来解决这个问题的。
2. 什么是插入意向锁
我们来看看 MySQL 官网的介绍:
大致翻译下一下就是这样:
插入意向锁是一种在 INSERT 操作之前设置的一种间隙锁,插入意向锁表示了一种插入意图,即当多个不同的事务,同时往同一个索引的同一个间隙中插入数据的时候,它们互相之间无需等待,即不会阻塞(要是单纯按照之前间隙锁的理论,必须要等一个间隙锁释放了,下一个事务才可以往相同的间隙处插入数据)。假设有值为 4 和 7 的索引记录,现在有两个事务,分别尝试插入值为 5 和 6 的记录,在获得插入行的排他锁之前,每个事务使用插入意向锁锁定 4 和 7 之间的间隙,但是这两个事务不会相互阻塞,因为行是不冲突的。
这就是插入意向锁。
3. 实践
小伙伴们注意,松哥之前和大家聊 Gap Lock,说过这个是可重复读(REPEATABLE READ)这个隔离级别下特有的产物,那么现在 Insert Intention Lock 是一种特殊的 Gap Lock,当然也是在可重复读这个隔离级别下生效。
接下来我们通过两个个简单的案例来演示一下插入意向锁。
3.1 案例一
我们的表结构以及数据和第一小节一致。
首先我们在会话 A 中,执行如下代码:
现在会话 A 中的事务没有提交。
接下来我们在会话 B 中,也执行一个插入操作:
我们发现会话 B 也可以正常执行,没有发生阻塞。
这说明,两个插入意向锁之间是兼容的,可以共存的。
3.2 案例二
我们再来看一个不兼容的例子。
首先在会话 A 中执行如下 SQL 查询 age 大于 80 的记录,并添加排他锁:
接下来在会话 B 中,执行如下代码插入一行数据:
小伙伴们看到,这个操作会被阻塞!阻塞的原因在于,插入意向锁和排他锁之间是互斥的。
趁着发生阻塞的这会,在会话 C 中,我们通过在前面文章中所使用的 show engine innodb status\G
指令,来查看下加锁的情况,重点看 TRANSACTION 节点:
在输出的内容中,红色框选中的地方,清楚的表明了插入意向锁的存在。
4. 小结
总结一下:
插入意向锁虽然名字中有意向二字,但实际上是一个特殊的间隙锁。
插入意向锁之间不互斥。
插入意向锁和排他锁之间互斥。
好啦,有问题欢迎留言讨论。
相关推荐:《Linux视频教程》
以上就是一文聊聊MySQL中的插入意向锁的详细内容,更多请关注php中文网其它相关文章!