MySQL解决幻读的方法

59次阅读
没有评论

共计 1640 个字符,预计需要花费 5 分钟才能阅读完成。

自动写代码机器人,免费开通

这篇文章将为大家详细讲解有关 MySQL 解决幻读的方法,丸趣 TV 小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

一、什么是幻读

在一次事务里面,多次查询之后,结果集的个数不一致的情况叫做幻读。

而多出来或者少的哪一行被叫做 幻行

二、为什么要解决幻读

在高并发数据库系统中,需要保证事务与事务之间的隔离性,还有事务本身的一致性。

三、MySQL 是如何解决幻读的

如果你看到了这篇文章,那么我会默认你了解了 脏读、不可重复读与可重复读。

1. 多版本并发控制(MVCC)(快照读)

多数数据库都实现了多版本并发控制,并且都是靠保存数据快照来实现的。

以 InnoDB 为例,每一行中都冗余了两个字断。一个是行的创建版本,一个是行的删除(过期)版本。版本号随着每次事务的开启自增。事务每次取数据的时候都会取创建版本小于当前事务版本的数据,以及过期版本大于当前版本的数据。

普通的 select 就是快照读。

select * from T where number = 1;

原理:将历史数据存一份快照,所以其他事务增加与删除数据,对于当前事务来说是不可见的。

2. next-key 锁(当前读)

next-key 锁包含两部分

记录锁(行锁)

间隙锁

记录锁是加在索引上的锁,间隙锁是加在索引之间的。(思考:如果列上没有索引会发生什么?)

select * from T where number = 1 for update;
select * from T where number = 1 lock in share mode;
insert
update
delete

原理:将当前数据行与上一条数据和下一条数据之间的间隙锁定,保证此范围内读取的数据是一致的。

其他:MySQL InnoDB 引擎 RR 隔离级别是否解决了幻读
引用一个 github 上面的评论 地址:

Mysql 官方给出的幻读解释是:只要在一个事务中,第二次 select 多出了 row 就算幻读。
a 事务先 select,b 事务 insert 确实会加一个 gap 锁,但是如果 b 事务 commit,这个 gap 锁就会释放(释放后 a 事务可以随意 dml 操作),a 事务再 select 出来的结果在 MVCC 下还和第一次 select 一样,接着 a 事务不加条件地 update,这个 update 会作用在所有行上(包括 b 事务新加的),a 事务再次 select 就会出现 b 事务中的新行,并且这个新行已经被 update 修改了,实测在 RR 级别下确实如此。

如果这样理解的话,Mysql 的 RR 级别确实防不住幻读

有道友回复 地址:

在快照读读情况下,mysql 通过 mvcc 来避免幻读。
在当前读读情况下,mysql 通过 next-key 来避免幻读。
select * from t where a=1; 属于快照读
select * from t where a=1 lock in share mode; 属于当前读

不能把快照读和当前读得到的结果不一样这种情况认为是幻读,这是两种不同的使用。所以我认为 mysql 的 rr 级别是解决了幻读的。

先说结论,MySQL 存储引擎 InnoDB 隔离级别 RR 解决了幻读问题。

如引用一问题所说,T1 select 之后 update,会将 T2 中 insert 的数据一起更新,那么认为多出来一行,所以防不住幻读。看着说法无懈可击,但是其实是错误的,InnoDB 中设置了 快照读 和 当前读 两种模式,如果只有快照读,那么自然没有幻读问题,但是如果将语句提升到当前读,那么 T1 在 select 的时候需要用如下语法:select * from t for update (lock in share mode) 进入当前读,那么自然没有 T2 可以插入数据这一回事儿了。

注意
next-key 固然很好的解决了幻读问题,但是还是遵循一般的定律,隔离级别越高,并发越低。

关于“MySQL 解决幻读的方法”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。

向 AI 问一下细节

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-12-04发表,共计1640字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)