MySQL选用可重复读之前一定要想到的事情(无索引加锁验证)

之前的实验,提到过一个场景

当前读(锁定读)加锁情况.

读提交 可重复读
主键索引 锁定主键索引
锁定主键索引
唯一索引 锁定唯一索引的值和主键索引的值
锁定唯一索引的值和主键索引的值
普通索引 锁定普通索引的值和主键索引的值
锁定普通索引的值和主键索引的值,普通索引增加间隙锁
无索引 锁定所有的主键索引,在服务器层对不符合条件的记录解锁
锁定所有的主键索引和主键索引的间隙

但是如何验证读提交隔离级别,会锁定所有主键主键,而在服务器层解锁呢?
http://blog.itpub.net/29254281/viewspace-1398273/

实验数据如下:
create table t
(
    a int primary key,
    b int,
    c int
) engine=innodb;

insert into t 
values
(1,10,10),
(3,10,20),
(5,20,30),
(7,20,40),
(9,20,50);
commit;

首先,可重复读隔离级别.
终端一:
select * from t where b=20 and c=30 for update;

终端二:
delete from t where b=20 and c=50;
阻塞

查看锁情况
select * from information_schema.innodb_locks;

可以看到锁定的数据是主键索引 1
这是因为终端一已经锁定了所有的主键索引和主键索引间隙.
终端二获取第一个主键索引就被阻塞.

同样的过程,改为读提交隔离级别.
终端一
select * from t where b=20 and c=30 for update;

终端二
delete from t where b=20 and c=50;
阻塞

查看锁情况
select * from information_schema.innodb_locks;


可以看到锁定了主键索引 5

这验证了何老师的说法,
就是在读提交隔离级别,对所有的主键索引上锁,在服务器层释放不符合条件的锁,
也就是说终端一锁定了所有的主键索引,在服务器层释放了其他主键索引的锁,只保留了a=5的锁.
终端二开始加锁,加到a=5的主键索引不能获取,所以阻塞

从现象看,如果终端一的语句不走二级索引或者主键索引,终端二的语句都会阻塞,
但是不同的是,可重复读锁定所有主键索引和主键索引间隙,
而读提交最终只会锁定相关记录的主键索引.

那么在读提交的隔离级别下,下面的语句不会阻塞
select * from t where a=1 for update;

而在可重复读隔离级别下,上面的语句就会阻塞.

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。