mysql间隙锁解决幻读

发布时间: 2023-11-21 11:04 阅读: 文章来源:1MUMB859PS
只是描述了mvcc解决不可重复读的情况,并没有描述如何解决幻读的。

幻读:侧重于insertdelete这种操作,第一次查出生成视图之后,即便有别的事务insertdelete,也不影响后续的查询。

首先解释下本次涉及的3种锁:

X锁:俗称写锁/排他锁,即加锁之后,不允许别的事务来修改当前数据。GAP锁:俗称间隙锁,就是锁住某个范围(RR级别解决幻读的关键)Next-Key锁:GAP锁+记录本身

着重强调一下,所有锁,都是针对索引的,锁的是索引,记住。如果没有索引,那就芭比Q了。

八股文:

B+tree非叶子节点只存储索引,所有叶子节点之间都有一个链指针,不存储数据,数据记录都存放在叶子节点中。

如下图所示:

上面是B+tree的数据结构,一定要记住叶子节点,里面包含了索引和data(主键/其他数据)。

有一点需要说明:叶子节点是按页存储的,页之间是双向链表,页里面的叶子节点是单向链表。

来个预热:

场景:

1:表结构(id是主键,count为普通索引):

开启事务1:

先查询count = 5,生成视图。

开始事务2:

此时插入一条count = 4的数据,很明显,被阻塞住了。

为啥要阻塞count = 4的记录呢?因为RR级别下,其实是加了GAP锁,不允许插入某个范围的值,从而避免了幻读的出现,那么这个范围是怎么定义的呢?

这是官网的,应用于我上面的例子,锁住的就是(3,5],(5,7],左开右闭。

好了,大家都散了吧。结论已经得出了:

加了范围锁,不允许插入数据,所以不会出现幻读的情况,范围如上。

什么,你反对?

对于GAP的范围,看到网上很多讨论,有的说是测试的左开右闭,也有说测试的左闭右开

这里,我想说,虽然实践是检验真理的标准,但是实践的前提是,你得明白实践方式对不对。

好,我们继续,上面的测试情况:

可以具体成上图,因为是普通索引,所以data只包含了主键。

那么锁住的是哪一块呢?

锁的其实是上述的区间,而左开右闭,左闭右开都是错误的。要看插入的位置

超出那个区间的就可以插入,反之即不可以插入,这个位置是按主键排序的。

count=3,id=32,可以插入count=3,id=34,不可以插入count=7,id=76,不可以插入count=7,id=78,可以插入

我们可以验证一下:

1.count=3,id=32:

插入成功,没有阻塞。

2.count=3,id=34:

插入失败,阻塞。

3.count=7,id=76:

插入失败,阻塞。

4.count=7,id=78:

插入成功,没有阻塞。

验证GAP

这下是真的结束了,大家可以散了。

什么?还没走?那么来传授一个面试装13技巧:

如果是更新语句,尽量以主键为条件,唯一约束也可以,因为主键和唯一约束都只会把更新的那一行加X锁。再不济,也要是以普通索引去更新。

大忌:以非索引字段去更新,这样会导致所有的列都加X锁,此时所有的 insert/update 都无法操作。

验证(count已经改为非索引):

可以看到,阻塞住了。

查询INNODB_LOCKS

supremum pseudo-record:表示无穷大

•••展开全文
相关文章