InnoDB 是如何解决幻读的

科技资讯 投稿 7900 0 评论

InnoDB 是如何解决幻读的

前言

事务隔离级别

事务隔离是数据库处理的基础之一,是 ACID 中的 I。在 MySQL 的 InnoDB 引擎中支持在 SQL:1992 标准中的四种事务隔离级别,如下图所示,其中 P1 表示脏读(Dirty read),P2 表示不可重复读(Dirty read),P3 表示幻读(Phantom)。

多个事务同时进行更改和执行查询时微调性能与结果的可靠性、一致性和可再现性之间的平衡的设置。是一种性能与结果可靠性间的 trade off

什么是幻读

幻读是什么,官方文档的描述如下:

result set of a query, but not in the result set of an earlier query。

范围查询操作。总结下,幻读就是:在同一个事务中,在前后两次查询相同范围时,两次查询得到的结果是不一致的。所以幻读会产生数据一致性问题。

InnoDB 解决幻读方式

select * from user where id = 9527 for update;

这时就会产生一个记录锁(也就是行锁),锁定 id = 9527 这个索引。

范围时,两次查询得到的结果是不一致」。注意,这里强调的是范围查询。

select * from user where id > 9530 and id < 9535 for update;

此时,另外一个语句再执行一如下这条 insert 语句时,需要被阻塞,直到上面这个获得锁的事务释放锁后才能执行。

insert into user(id, name, age values(9533, 'Jack', 44;

为此,InnoDB 引入了「间隙锁」,它的主要功能是锁定一段范围内的索引记录。比如上面查询 id > 9530 and id < 9535 的时候,对 B+ Tree 中的(9530,9535)这个开区间范围的索引加间隙锁。

select * from user where id > 9530 for update;

上面这条查询语句是针对 id > 9530 这个条件加锁,那么此时它需要锁定多个索引区间,所以在这种情况下 InnoDB 引入了「next-key 锁」机制。其实 next-key 锁的效果相当于间隙锁和记录锁的合集,记录锁锁定存在的记录行,间隙锁锁住记录行之间的间隙,而 next-key 锁它锁住的是两者之和。

非唯一索引列上都会存在一把 next-key 锁,当某个事务持有该数据行的 next-key 锁时,会锁住一段左开右闭区间的数据。因此,当通过 id > 9530 这样一种范围查询加锁时,会加 next-key 锁,锁定区间是范围是:

加锁的范围,间隙锁只锁定两个索引之间的引用间隙,而 next-key 锁会锁定多个索引区间,它包含「记录锁」和「间隙锁」。所以,当我们使用了范围查询,不仅仅命中了已存在的 Record 记录,还包含了 Gap 间隙。

总结

虽然在 InnoDB 引擎中通过间隙锁和 next-key 锁的方式解决了幻读问题,但是加锁之后会影响到数据库的并发性能,因此,如果对性能要求较高的业务场景中,建议把隔离级别设置成 RC(READ COMMITTED),这个级别中不存在间隙锁,但是需要考虑到幻读问题会导致的数据一致性。

编程笔记 » InnoDB 是如何解决幻读的

赞同 (43) or 分享 (0)
游客 发表我的评论   换个身份
取消评论

表情
(0)个小伙伴在吐槽