Mysql可重复读隔离级别下如何解决幻读

  • Post author:
  • Post category:mysql




一些概念


幻读

:在一次事务中,同一条select语句在先后两次查询中得到了不同的记录。

MySql可重复读隔离级别下解决了幻读。


快照读的幻读用MVCC解决,当前读的幻读用间隙锁解决


MVCC,快照读和当前读的概念:

MVCC及实现原理


下面只分析当前读的幻读。

一些锁的概念:


共享锁(Shared)

:又称S锁,读锁,共享锁,加了S锁其他事务可以读,不可以写。


排它锁(Exclusive)

:又称X锁,写锁,排它锁,加了X锁其他事务不可以读也不可以写。


record lock

:索引加锁。单条索引记录上加锁,record lock锁住的永远是索引,而非记录本身,即使表上没有任何索引,innodb会在每条记录上生成默认的聚簇索引。当一条sql语句没有任何索引时,会在每一条聚簇索引后面加X锁,这个表类似于表锁,但原理是不同的。


GAP lock

:间隙锁。在记录索引的间隙中加锁。


跟间隙锁存在冲突关系的,是“往这个间隙中插入一个记录”这个操作。间隙锁和间隙锁之间不存在冲突关系。



next-key lock

:由record lock+GAP lock组成,每次锁住的不光是需要使用的数据,还会锁住这些数据附近的数据。

在可重复读隔离级别下,加锁的基本单位是next-key lock,是前开后闭的。



具体加锁说明

有如下一张person表,其中id是主键索引。name是二级索引。

id name age
1 a张三 20
3 b李四 23
6 c王五 20
12 d赵六 25



使用主键索引进行等值查询

  • 如果记录存在,因为主键具有唯一性,所以只需要添加一个行锁(record lock)。
SELECT * FROM person WHERE id=3 LOCK IN SHARE MOOE;

在这里插入图片描述

深色表示加上了行锁,具体是S锁。

  • 如果记录不存在。为了防止幻读会使用间隙锁。
SELECT * FROM person WHERE id=5 LOCK IN SHARE MOOE;

在这里插入图片描述

会在3和6之间加上间隙锁。

插入:

SELECT …LOCK IN SHARE MOOE和SELECT …FOR UPDATE的区别

SELECT …LOCK IN SHARE MOOE走的是IS锁(意向共享锁),即在符合条件的rows上都加了共享锁。

SELECT …FOR UPDATE走的是IX锁(意向排它锁),即在符合条件的rows上都加了排它锁。

如果在上面的语句中换成了SELECT …FOR UPDATE,大致的流程是一样的,只不过行锁中的S锁换成了X锁。



使用主键索引进行范围查询

  • 查询语句
SELECT * FROM person WHERE id>3 LOCK IN SHARE MOOE;

在这里插入图片描述

  • update语句

    – 如果update语句没有更新二级索引,和前面是一样的。

    – 如果update更新了二级索引。
UPDATE SET name='春花' WHERE id>3;

在这里插入图片描述

会对二级索引对应的行加上X锁。



使用二级索引进行等值查询

SELECT * FROM person WHERE name='张三'LOCK IN SHARE MODE;



因为二级索引不是唯一的,二级索引会加上行锁和间隙锁,主键索引会加上行锁。



使用二级索引进行范围查询

SELECT * FROM person WHERE name>='李四'  LOCK IN SHARE MOOE;

在这里插入图片描述

首先会查找>=’李四’的第一条记录,在二级索引中加上行锁和间隙锁,在对应的主键索引中加上行锁,判断下一个记录是否符合要求,继续重复。



版权声明:本文为dycyjb原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。