欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

MySQL 是如何解决幻读的

程序员文章站 2022-06-14 16:40:35
...

1.什么是幻读

在一次事务里面,多次查询之后,结果集的个数不一致的情况叫做幻读。而多或者少的那一行被叫做 幻行。
就像出现了幻觉一样 所以叫幻读。

2.为什么要解决幻读

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

3.MySQL 是如何解决幻读的

3.1 多版本并发控制(MVCC)(快照读/一致性读)

多数数据库都实现了多版本并发控制,并且都是靠保存数据快照来实现的。
InnoDB 为例。可以理解为每一行中都冗余了两个字段,一个是行的创建版本,一个是行的删除(过期)版本。
具体的版本号(trx_id)存在 information_schema.INNODB_TRX 表中。
版本号(trx_id)随着每次事务的开启自增。
事务每次取数据的时候都会取创建版本小于当前事务版本的数据,以及过期版本大于当前版本的数据。
普通的 select 就是快照读。

select * from T where number = 1;

原理:将历史数据存一份快照,所以其他事务增加与删除数据,对于当前事务来说是不可见的。
Select: 1 选择版本早于当前事务本版的数据行; 2 行的删除版本要么未定义,要么大于当前事物版本号,确保事务读取到的行,在事务开始之前未删除;
insert: innoDB确保新的行保存当前系统版本号作为行版本号;
delete: innoDB确保删除的行保存当前系统版本号作为行删除标识;
update:InnoDB 为插入一行新的纪录,保存当前系统版本号作为行版本号,同时保存当前系统版本号到原来的行作为行删除标识

3.2 Next-Key Lock

MySQL InnoDB支持三种行锁定方式:
行锁(Record Lock):锁直接加在索引记录上面。
间隙锁(Gap Lock):锁加在不存在的空闲空间,可以是两个索引记录之间,也可能是第一个索引记录之前或最后一个索引之后的空间。
Next-Key Lock:行锁与间隙锁组合起来用就叫做Next-Key Lock。
当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但并不存在的记录,叫做“间隙(GAP)”,InnoDB也会对这个“间隙”加锁,这种锁机制就是所谓的间隙锁(Next-Key锁)。
举例来说,假如user表中只有101条记录,其empid的值分别是 1,2,…,100,101,下面的SQL:

select * from  user where user_id > 100 for update;

是一个范围条件的检索,InnoDB不仅会对符合条件的user_id值为101的记录加锁,也会对user_id大于101(这些记录并不存在)的“间隙”加锁。
产生幻读的原因是,行锁只能锁住行,但是新插入记录这个动作,要更新的是记录之间的“间隙”。因此,为了解决幻读问题,InnoDB 只好引入新的锁,也就是间隙锁 (Gap Lock)。

InnoDB使用间隙锁的目的,一方面是为了防止幻读,以满足相关隔离级别的要求,对于上面的例子,要是不使用间隙锁,如果其他事务插入了user_id大于100的任何记录,那么本事务如果再次执行上述语句,就会发生幻读;另外一方面,是为了满足其恢复和复制的需要

【注意】 MySQL InnoDB的可重复读并不保证避免幻读,需要应用使用加锁读来保证。而这个加锁度使用到的机制就是next-key locks。
本事务中第一次读取出一行,做了一次更新后,另一个事务里提交的数据就出现了。也可以看做是一种幻读。

相关标签: 面试突进 mysql