初始化语句
sql
1 | mysql> CREATE TABLE `t` ( |
隔离级别
sql
1 | mysql> select @@tx_isolation; |
幻读是什么?
sessionA | sessionB | seesionC | |
---|---|---|---|
T1 | begin; | ||
select * from t where d=5 for update;/*Q1/ result:(5,5,5) | |||
T2 | update t set d=5 where id=0; | ||
T3 | select * from t where d=5 for update;/*Q2/ result:(0,0,5),(5,5,5) | insert into t values(1,1,5); | |
T4 | |||
T5 | select * from t where d=5 for update;/*Q3/ result:(0,0,5),(1,1,5),(5,5,5) | ||
T6 | commit; |
Code
1 | 1.Q1 只返回 id=5 这一行; |
其中,Q3 读到 id=1 这一行的现象,被称为“幻读”。也就是说,幻读指的是一个事务在前后两次查询同一个范围的时候,后一次查询看到了前一次查询没有看到的行。
Code
1 | 1.在可重复读隔离级别下,普通的查询是快照读,是不会看到别的事务插入的数据的。因此,幻读在“当前读”下才会出现。 |
幻读有什么问题?
- 首先是语义上的。
- 其次,是数据一致性的问题。
- 也就是说,即使把所有的记录都加上锁,还是阻止不了新插入的记录
如何解决幻读?
产生幻读的原因是,行锁只能锁住行,但是新插入记录这个动作,要更新的是记录之间的“间隙”。因此,为了解决幻读问题,InnoDB 只好引入新的锁,也就是间隙锁 (Gap Lock)。间隙锁和 next-key lock 的引入,帮我们解决了幻读的问题,但同时也带来了一些“困扰”。间隙锁的引入,可能会导致同样的语句锁住更大的范围,这其实是影响了并发度的。
- 间隙锁是在可重复读隔离级别下才会生效的