InnoDB可重复读隔离级别下如何避免幻读
- 表象:快照读(非阻塞读)–伪MVCC
- 内在:next-key锁(行锁+gap锁)
next-key锁(行锁+gap锁)
- 行锁
- Gap锁
对主键索引或者唯一索引会用Gap锁吗
- 如果where条件全部命中,则不会用Gap锁,只会加记录锁
- 如果where条件部分命中或者全不命中,则会加Gap锁
session1
select @@tx_isolation;
start transaction;
delete from tb where id = 9;
rollback;
delete from tb where id = 7; //删除一个不存在的id
session2
select @@tx_isolation;
start transaction;
insert into tb values('i',10);
rollback;
insert into tb values('i',8); //插入不存在的值
我们进行删除不存在的id的时候,周围的数也被blok住了,说明gap锁是有范围的。
session1
select * from tb where id in(5,7,9) lock in share mode;
在事务未提交前。
session2
insert into tb values('i',4);//成功
insert into tb values('ii',7);//不成功,被blok住了
insert into tb values('ii',8);//不成功,被blok住了
insert into tb values('ii',10);//成功
这次我们来精确命中全部数据
session1
select * from tb where id in (5,6,9) lock in share mode;
session2
insert into tb values("ii",7);//成功的
insert into tb values("iii",8);//成功执行
Gap锁会在非唯一索引或者不走索引的当前读中
- 非唯一索引
session1
delete from tb1 where id = 9;
session2
insert into tb1 values('test',9);
#6-11之间会被blok
insert into tb1 values('test',5);
insert into tb1 values('test1',7);//被blok住了,说明有间隙锁
insert into tb1 values('test1',12);
我们再细节一点
insert into tb1 values('bb',6); //成功了,叶子节点按照首字母b排序的
insert into tb1 values('dd',6); //不成功
- 不走索引
创建tb2
id是没有任何索引的一个列
#5-11开外
insert into tb2 values('test',2);