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

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;

Mysql可重复读隔离级别下如何解决幻读_第1张图片
深色表示加上了行锁,具体是S锁。

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

Mysql可重复读隔离级别下如何解决幻读_第2张图片
会在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;

Mysql可重复读隔离级别下如何解决幻读_第3张图片

  • update语句
    – 如果update语句没有更新二级索引,和前面是一样的。
    – 如果update更新了二级索引。
UPDATE SET name='春花' WHERE id>3;

Mysql可重复读隔离级别下如何解决幻读_第4张图片

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

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

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

Mysql可重复读隔离级别下如何解决幻读_第5张图片
因为二级索引不是唯一的,二级索引会加上行锁和间隙锁,主键索引会加上行锁。

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

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

Mysql可重复读隔离级别下如何解决幻读_第6张图片
首先会查找>='李四’的第一条记录,在二级索引中加上行锁和间隙锁,在对应的主键索引中加上行锁,判断下一个记录是否符合要求,继续重复。

你可能感兴趣的:(java,mvcc,mysql)