什么是幻读?

  InnoDB默认级别为可重复读,可重复读会产生问题就是幻读。事务A按照一定条件进行数据读取,期间事务B插入了相同搜索条件的新数据,事务A再次按照原先条件进行读取时,发现了事务B新插入的数据称之为幻读。如果事务中都是用快照读,那么不会产生幻读的问题,但是快照读和当前读一起使用的时候就会产生幻读。

  不可重复读侧重于update这种操作,同一条数据前后读起来不一样的情况,幻读侧重于insert delete这种操作,前后两次select 数据的数量会发生变化

  举个例子:

    事务A  第一步  select *       第二步  update 所有字段        第三步  再次select *      

    事务B  执行了insert 一条语句

    幻读第一种情况: 当事务A 刚执行完第一步,事务B insert一条,导致事务A update执行完,再次select发现多了一条数据

    幻读第二种情况: 当事务A 刚执行完第二步,事务B insert一条,导致事务A 再次select 发现有一条数据没有update字段

 

InnoDB如何解决幻读的?

  Mvcc+行锁+间隙锁

 

什么是间隙锁?

  正常等值条件 并且值存在的情况下加的是行锁

  如果等值条件 值不存在的情况下加的是间隙锁,或者范围查询,加的也是间隙锁

  举个例子:

  mysql 幻读_数据

  根据主键id,不只是有五个行锁,还会有六个间隙锁,左开右闭原则,(-∞,5](5,10](10,15](15,20](20,25](25,+supernum]

  例如 select * from table where id = 10 for update;   等值条件,id是存在的,加行锁就可以了

  select * from table where id = 7 for update;  等值条件,id不存在,加(5,10] 间隙锁,这范围间不允许插入数据,直到这个事务提交完成释放锁

  select * from table where id > 24;  范围条件,加间隙锁

  通过行锁+间隙锁的机制保证了事务A select之后,其他事务相应的insert操作会阻塞

 

间隙锁跟MVCC一起工作。实现事务处理:

   Repeatable Read隔离级别: 采用Next-key Lock(间隙锁) 来解决幻读问题.因此 Mysql 在Repeatable下面 幻读,可重复读,脏读 三者都不会发生

   Read Committed隔离级别:采用Record锁,不会出现脏读,但是会产生"幻读"问题. 也会出现可重复读

间隙锁简介:

  MySQL InnoDB支持三种行锁定方式:InnoDB的默认加锁方式是next-key 锁

    行锁(Record Lock):锁直接加在索引记录上面,锁住的是key。

   间隙锁(Gap Lock):锁定索引记录间隙,确保索引记录的间隙不变。间隙锁是针对事务隔离级别为可重复读或以上级别而已的。

   Next-Key Lock :行锁和间隙锁组合起来就叫Next-Key Lock。 

  默认情况下,InnoDB工作在可重复读(Repeatable Read)隔离级别下,并且会以Next-Key Lock的方式对数据行进行加锁,这样可以有效防止幻读的发生。Next-Key Lock是行锁和间隙锁的组合,当InnoDB扫描索引记录的时候,会首先对索引记录加上行锁(Record Lock),再对索引记录两边的间隙加上间隙锁(Gap Lock)。加上间隙锁之后,其他事务就不能在这个间隙修改或者插入记录。 read committed隔离级别下Gap Lock在InnoDB的唯一作用就是防止其他事务的插入操作,以此防止幻读的发生。Innodb自动使用间隙锁的条件:
  (1)必须在Repeatable Read级别下
  (2)检索条件必须有索引(没有索引的话,mysql会全表扫描,那样会锁定整张表所有的记录,包括不存在的记录,此时其他事务不能修改不能删除不能添加)