数据库
首页 > 数据库> > JAVA面试准备之数据库 锁模块(5)InnoDB可重复读隔离级别下如何避免幻读

JAVA面试准备之数据库 锁模块(5)InnoDB可重复读隔离级别下如何避免幻读

作者:互联网

InnoDB可重复读隔离级别下如何避免幻读?

表象:快照读(非堵塞读)

    在Repeatable-read隔离级别下,如果先在别的事务操作数据之前,创建了快照读,不管别的事务怎么操作数据,当前事务再次使用快照读时,查到的依旧是老版本的数据。

内在:next-key锁(行锁+gap锁)

    真正防止幻读发生是因为事务在Repeatable-read隔离级别以上(包括)对数据加了next-key锁。next-key锁由行锁和gap锁组成。

 

next-key锁

由行锁和gap锁组成

行锁就是对行记录加的锁。

Gap锁

1.目的是防止同一事务的两次当前读出现幻读的情况。

2.Repeatable-read级别以上支持Gap锁。

3.在RR级别下,对主键索引或者唯一索引会用Gap锁的情况:

如果where条件全部命中,则不会用Gap锁,只会加行锁。

Select * from . where id=1,2,3 这三条记录都能查得到,则称为全部命中

如果where条件部分命中或者全不命中,则会加Gap锁

4.Gap锁会用在非唯一索引或者不走索引的当前读中

 

唯一索引加Gap锁的过程:先找到id的索引加锁,在找到这条记录对应的主键锁加锁

 

非唯一索引加Gap锁的过程:

加锁区间是左开右闭。

这边是对(6,9],(9,11]区间的数据加Gap锁

 

不走索引加Gap锁的过程:

当前读不走索引时,对整张表上锁

 

举例:

两个session的事务隔离级别均为Repeatable-read

两个session同时开启事务。

 

情况1:唯一索引:全部命中数据

Session1锁住id为9的数据(id是唯一索引)

 

Session2插入数据,成功:

 

总结:如果当前事务走的是唯一索引,并且全部命中数据,不会加Gap锁

 

情况2:唯一索引:全不命中

在表里7,8的数据不存在

 

Session1删除一条不存在的数据:

 

Session2插入数据8,造成了堵塞

 

证明7之间的间隙被锁住了,即加了Gap锁

 

情况3:唯一索引:部分命中

在表里7,8的数据不存在

Session1:

 

Session2:插入4,成功。

插入7,堵塞。

插入8,堵塞。

插入10,成功。

说明对小于5或者大于9的数据没有加锁,对5-9之间的数据加Gap锁。

 

情况4:非唯一索引

Session1:

 

Session2:

插入5,12成功

插入7堵塞。

这边是对(6,11]区间的数据加Gap锁。

区间还跟主键相关,即({cc,6},{f,11}]上了Gap锁

6对应的name是cc

插入(bb,6)成功

插入(dd,6)堵塞

 

情况5:不走索引

 

Session1:

 

Session2:

 

全部数据被锁住

标签:JAVA,Session1,插入,幻读,Gap,索引,InnoDB,命中,数据
来源: https://blog.csdn.net/qq_31965925/article/details/104826238