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