mysql幻读怎么办 mysql 幻读mvcc

MySQL可重复读防止幻读 接上篇事务隔离级别和幻读,留了个坑,没想到竟然过了10天 , 时间不注意真的过的好快 。顺便提下,图片链接是属于网站的,开发自己的图床迫在眉睫 , 万一哪天迁移就要做很多额外工作,一些概念或者思路用图片表达更直观清楚 。
回到正题,之前提到一般情况下MySQL的InnoDB引擎在可重复读的情况下是没法保证不出现幻读的 , 但实际情况是MySQL可以通过加锁来防止幻读的出现,这种锁定通过Next-key机制来实现,是属于记录锁和间隙锁(Gap锁)的结合 。
引申,行级别锁的三种算法:
举个存在唯一索引和辅助索引的例子做说明:
执行select * from test where b = 3 for update
存在两个索引,分别加锁,唯一主键列a加record lock ,辅助索引列b加next-key lock (1,3) 以及给下一个值的区间(3,6)加gap锁;
因此在另一个事务里执行以下语句都会阻塞,具体分析:
第一个阻塞因为加了唯一索引的record lock a = 5;
第二个主键插入4,符合条件,但是根据辅助索引b 的范围, b = 2 在(1,3)中,同样阻塞;
第三个a =6 不在主键a锁定范围,b = 5 也不在辅助索引b 的范围(1,3)中,但在另一个gap锁范围(3,6)中,因此也阻塞;
这种锁定情形下,可以执行的包括类似语句:
insert的特殊情况
对于insert 会检查下一条记录是否被锁定,如上述例子有 select * from test where b = 3 for update 插入 insert into test select 2,2 会检测到b = 3 已经被锁定 , 而 insert into test select 2,0 可以执行;
[1]:《MySQL技术内幕:InnoDB存储引擎》-第六章:锁
正确理解MYSQL的幻读一、定义
1、幻读MYSQL官方叫法是Phantom Rows,意为鬼影行或者幻影行,请看官方定义:
The so-called phantom problem occurs within a transaction when the same query produces different sets of rows at different times. For example, if a [ SELECT ] is executed twice, but returns a row the second time that was not returned the first time, the row is a “phantom” row.
翻译一下:
所谓的幻影行问题是指,在同一个事务中,同样的查询语句执行多次,得到了不同的行结果集 。
例如,如果同一个SELECT语句执行了两次,第二次执行的时候比第一次执行时多出一行,则该行就是所谓的幻影行 。
2、幻读与不可重复读的区别
从官方的定义来看 , 幻读的定义侧重于多条记录,就是记录条数的变化 , 而不可重复读侧重于单条记录数据的变化,这样区分原因在于解决幻读需要范围锁,解决不可重复读只需要单条记录加锁
二、InnoDB的REPEATABLE READ级别
InnoDB支持由SQL1992标准描述的所有四个事务隔离级别,默认隔离级别是 REPEATABLE READ 。
1、快照读:
在RR模式下,第一次读取会建立快照,后续查询会读取快照 。
这意味着,如果在同一事务中发出多个普通[ SELECT ](非锁定)语句,则这些 [ SELECT ]语句的结果也是一致的 。
2、[locking reads](锁定读取,又叫当前读)
[ SELECT ]语句中使用 FOR UPDATE 或 FOR SHARE
3、行锁
在RR模式下 , 使用当前读以及 [ UPDATE ]和 [ DELETE ]语句会对数据记录加行锁,锁定范围取决于该语句使用的是具有唯一搜索条件的唯一索引还是范围类型搜索条件 。
三、InnoDB的READ COMMITTED级别
1、在RC模式下 , 每次读取都会刷新快照,因此不能保证可重复读
2、在RC模式下,使用当前读以及 [ UPDATE ]和 [ DELETE ]语句会对数据记录加行锁,但是不会加范围锁,间隙锁定仅用于外键约束检查和重复键检查 。

推荐阅读