mysql RC 隔离级别下为什么需要 next key lock 来保证唯一索引有效性

Posted 渔夫数据库笔记

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mysql RC 隔离级别下为什么需要 next key lock 来保证唯一索引有效性相关的知识,希望对你有一定的参考价值。

 一:RC 隔离级别下通过next key lock 来保证唯一约束生效

  我们知道在RC隔离级别中几乎不会出现 Gap Lock,但是官方文档中列出了如下两个例外情况(在外键约束和唯一性约束时还是会使用Gap Lock,即使在RC隔离级别下)。

 

二:未使用 next key lock,RC隔离级别下出现唯一约束失效BUG

我实话按我个人的理解,RC隔离级别下确实不需要使用Gap Lock 来保证唯一性约束。有人跟我有同样的想法,并且mysql 做了修改去掉了使用Gap Lock 来保证唯一性,但是很不幸的是,修改后发生了唯一约束失效的BUG,bug地址如下:

bug#68021

  上面的bug中以及下面的阿里云内核月报文章中,都给出了触发bug的测试脚本

MySQL · 内核分析 · InnoDB主键约束和唯一约束的实现分析

在内核月报中给出的触发bug的例子如下:

Transaction 1:
begin;
delete from t1 where c2 = 5; // 加X NOT_GAP lock,成功
Transaction 2:
insert into t1 select 1,5; // 加S NOT_GAP lock,等待
Transaction 3:
insert into t1 select 2,5; // 加S NOT_GAP lock,等待
Transaction 1:
commit;
T1 释放X NOT_GAP lock
T2 加S NOT_GAP lock成功
T3 加S NOT_GAP lock成功(S锁互相兼容)
T2 加X insert intention lock成功(X IK和S RK兼容)
T3 加X insert intention lock成功(X IK和S RK,X IK均兼容)
T2 插入记录成功
T3 插入记录成功

三:我的疑惑

上面例子中看似解释是很合理的,但是我有一个疑惑,在 T1 提交后,T2,T3 确实会成功的加上 S NOT_GAP lock。但是有一个重要的环节好像被忽略了,那就是修改或者读取页面需要对页面加上RW-X-LATCH 或者RW-S-LATCH锁,所以正确的过程应该如下

1) T2 申请页面上的 RW-X-LATCH 锁,成功后进行唯一约束检查发现冲突,所以

T2 释放 RW-X-LATCH 并等待S NOT_GAP lock

2) T3 申请页面上的 RW-X-LATCH 锁,成功后进行唯一约束检查发现冲突,所以

T3 释放 RW-X-LATCH 并等待S NOT_GAP lock

3) T1事务提交

4) T1事务提交后,T2,T3获取了各自等待的 S NOT_GAP lock,但是他们获取的锁都是在没有 RW-X-LATCH 锁的保护下获得的,所以这时T2和T3 应该重新获取 RW-X-LATCH锁,在该锁的保护下重新判断加锁,因为这个过程是串行的,所以我认为不应该导致两条记录都被插入成功,最后只应该有一条插入成功

NOTE:第三部分只是个人的疑惑,能力有限,如果哪位大神对这一块比较清楚的,望请不吝赐教

以上是关于mysql RC 隔离级别下为什么需要 next key lock 来保证唯一索引有效性的主要内容,如果未能解决你的问题,请参考以下文章

MySQL RR和RC隔离级别区别

MySQL RR和RC隔离级别区别

mysql 事物隔离级别rr还是rc好

MySQL 默认隔离级别是RR,为什么阿里这种大厂会改成RC?

MySQL 默认隔离级别是RR,为什么阿里这种大厂会改成RC?

MySQL的RR和RC事务隔离级别加锁类型验证