本文共 3880 字,大约阅读时间需要 12 分钟。
联动贴: http://blog.itpub.net/29510932/viewspace-1814690/ ---------------------------- --------- -----------------------------------------接前文------------------------------------------------------------------------------------------------前文写了一些锁相关的东西,后半篇写一些各种情况下的锁的情况-------------------------------------------------------------------------------正文------------------------------------------------------------------------------------------------测试方法:两个session分别执行简单的insert/delete/update语句,模拟锁的情况测试环境:官方MySQL-5.6.26,隔离级别REPEATABLE-READ和READ COMMITTED测试内容:测试表student,试验分为六组,RR,RC两种隔离级别,唯一索引,非唯一索引,无索引三种情况,数据和表结构如下(根据实验的要求,可能简单改一下数据)1.RR隔离级别,非唯一索引 session1: delete from student where sid = 10005; session2: insert into student values(10006,'se10006'); insert into student values(10008,'se10008');insert into student values(10010,'se10010'); 分析: 从MySQL实现的角度来看,在sid上具备索引,根据MySQL加锁的特点,session1会在索引sid上加上X锁,但是sid是非唯一索引,如果只对sid=10005这一条记录加锁,并不能阻止其他的事务继续插入sid=10005的数据,从而会误删其他事务插入的sid=10005的数据,所以MySQL会在10005的前后加上GAP锁(间隙锁),阻止其他事务插入sid处于10005-10007和10007-10009区间的任何数据 加锁的示意图如下 所以10006和10008的数据刚好在GAP锁的范围之内,mysql锁的信息10010在GAP锁的范围之外(10010既不在10005-10007,也不再10007-10009范围内),所以能够正常的插入2.RR隔离级别,唯一索引session1:
delete from student where sid = 10005;
session2:
insert into student values(10006,'se10006');
insert into student values(10008,'se10008');
insert into student values(10010,'se10010');分析:
从MySQL实现的角度来看,在sid上具备索引,根据MySQL加锁的特点,session1会会在索引sid上加上X锁,
由于sid是唯一索引,所以对与MySQL来说,它能确认在这个索引上,至多只会存在一条数据满足sid=10005,唯一索引本身的特性会阻止其他的事务继续插入sid=10005的数据,从而防止误删其他事务插入的sid=10005的数据,
所以MySQL只需要在10005加上X锁,而无需加上GAP锁,锁住10005前后的间隙,所以session2的所有语句都不会阻塞。
加锁的示意图如下 MySQL的信息3.RR隔离级别,无索引
session1:
delete from student where sid = 10005;
session2:
insert into student values(10004,'se10004');
insert into student values(10008,'se10008');
insert into student values(10010,'se10010'); 分析:从MySQL实现的角度来看,在student表上没有索引,根据MySQL本身的特点,MySQL会自动创建一个隐藏的聚簇索引作为主键, 当delete操作执行时,student表不存在任何索引,所以MySQL会用X锁锁住所有的行,锁的标记位在自动创建的聚簇索引上; 当session2试图修改or操作student表的数据时,无法在聚簇索引上加锁,进行锁等待。 加锁示意图如下 MySQL的信息 可以看到由于不存在索引,session1锁住了整个表的所有行,而session2则在等待X锁的释放,X锁是加在自动生成的聚簇索引"GEN_CLUST_INDEX"上。 session2的其他语句有同样的效果,图略去。4.RC隔离级别,无索引
session1:
delete from student where sid = 10005;
session2:
insert into student values(10006,'se10006');insert into student values(10005,'se10005'); 分析:RC隔离级别,无索引的情况,session1依然会对表的所有行加上X锁,session2的操作会被阻塞 加锁情况:
然而实际情况如下这是因为MySQL在处理这种锁的情况的时候,会去过滤实际需要锁定的行(sid=10005),然后释放掉不需要的那些行的锁,实际上对所有行的加锁操作还是存在的;5.RC隔离级别,非唯一索引
session1:
delete from student where sid = 10005;
session2:
insert into student values(10006,'se10006'); update student set sname = '1111' where sid = 10005;update student set sname = '1111' where sid = 10006;
分析:
RC隔离级别,非唯一索引的情况,session1只会对表的符合条件的行加上X锁,这里补上两个update来看一下X锁的情况session2的执行情况,可以看到同样在操作10005的时候, 由于锁等待,对10005的update操作被阻塞了,但是对10006的操作是正常的 加锁情况同4 锁情况6.RC隔离级别,唯一索引
session1:
delete from student where sid = 10005;
session2:
insert into student values(10006,'se10006'); update student set sname = '1111' where sid = 10005; update student set sname = '1111' where sid = 10006;
分析:
同情况5,只会对符合条件的行加上X锁。 加锁情况同47.RR隔离级别这个情况单独写出来:当delete语句指定的行,在表当中找不到的时候,会有特殊的处理 表内容小改:session1:
delete from student where sid = 10007;
session2:
insert into student values(10006,'se10006');
insert into student values(10008,'se10008');
insert into student values(10010,'se10010'); 分析:student表存在唯一索引,在这种情况下,因为表中不存在这一行数据,所以MySQL会找到>10007且不符合条件的第一行数据,加上X锁,然后在这一条数据的前面加上GAP锁 加锁示意图 mysql的信息当存在非唯一索引时,与唯一索引是一样的加锁策略,在无索引的情况下,则是锁住表的全部行。 PS:写在最后,产生死锁的原因,是因为两个事务都需要同时持有多个锁, 但是他们分别持有对方需要的一部分锁。---------------------------------------------------------------------------------结尾---------------------------------------------------------------------------------------------- 前几个试验的时候,session2的insert貌似选的不是很合理,不过实际上GAP锁确实是有加持,在后面的第七种情况里面也能看出来 终于填完了锁的坑,接下来还有metadata lock, index_merge,还有啥来着......太多了....._(:з」∠)_ 转载地址:http://crjil.baihongyu.com/