幻读指的是一个事务在 前后两次查询同一个范围的时候,后一次查询看到了前一次查询没有看到的行。
可以看到,session A 里执行了三次查询,分别是 Q1、Q2 和 Q3。它们的 SQL 语句相 同,都是 select * from t where d=5 for update。这个语句的意思你应该很清楚了,查 所有 d=5 的行,而且使用的是当前读,并且加上写锁。现在,我们来看一下这三条 SQL 语句,分别会返回什么结果。
id=0 和 id=5 这两行;在 T4 时刻,session C 又插入一行(1,1,5),因此 T5 时刻 Q3 查出来的是 id=0、
id=1 和 id=5 的这三行。
其中,Q3 读到 id=1 这一行的现象,被称为“幻读”。也就是说,幻读指的是一个事务在 前后两次查询同一个范围的时候,后一次查询看到了前一次查询没有看到的行。
PS:说明
在可重复读隔离级别下,普通的查询是快照读,是不会看到别的事务插入的数据的。因 此,幻读在“当前读”下才会出现。上面 session B 的修改结果,被 session A 之后的 select 语句用“当前读”看到,不 能称为幻读。幻读仅专指“新插入的行”。 三.为什么会出现幻读即便你把所有的行都加上锁,一旦有别的会话插入新的记录,还是无法阻止幻读的产生,如上图的session C,可以通过间隙锁来解决这个问题。
至此,两个 session 进入互相等待状态,形成死锁。当然,InnoDB 的死锁检测马上就发 现了这对死锁关系,让 session A 的 insert 语句报错返回了。
间隙锁的引入,可能会导致同样的语句锁住更大的范围,这其实是影响了 并发度的。