标签:
今天上午和同事火热争论了一番,争来争去围绕的就锁的几个基本概念。
record lock、gap lock、next_key lock
当时争完后发现自己对锁的理解更加透彻了:事务的隔离级别就是通过锁来实现的啊。
RC:仅有record 锁
RR:有record和next_key锁
现在我们就来讨论在RR模式下,各种SQL语句的锁实现:
create table t1(id int primary key auto_increment,
col1 int not null default 0,
col2 varchar(20) not null default ‘‘,
col3 datetime not null default ‘2010-01-01 00:00:00‘);
首先写个生产测试数据的存储过程:
delimiter $$
create procedure proc_generate_data(in i_rec_num int,in i_prefix_name varchar(20),in i_is_order tinyint)
begin
declare rec_num int;
declare prefix_name varchar(20);
declare is_order tinyint;
declare i int;
set i=0;
set rec_num=i_rec_num;
set prefix_name=i_prefix_name;
set is_order=i_is_order;
loop1:while (i<rec_num) do
set @c1=floor(round(rand(),5)*100000);
set @c2=concat(prefix_name,@c1);
set @c3=now();
if is_order = 0 then
insert into t1(col1,col2,col3)values(@c1,@c2,@c3);
elseif is_order = 1 then
set @id= floor(round(rand(),5)*100000);
select 1 into @if_exist from t1 where id=@id;
if @if_exist != 1 then
insert into t1(id,col1,col2,col3)values(@id,@c1,@c2,@c3);
else
insert into t1(col1,col2,col3)values(@c1,@c2,@c3);
end if;
else
insert into t1(col1,col2,col3)values(2000,‘nihao‘,@c3);
end if;
set i= i+1;
end while loop1;
end $$
delimiter ;
生成测试数据:
顺序生产10000条 call proc_generate_data(10000,‘first‘,0);
非顺序生成10000条 call proc_generate_data(10000,‘second‘,1);
顺序生产10000条 call proc_generate_data(10000,‘third‘,0);
开始测试:
Insert
No.1 insert单条,只有主键索引,是record_lock还是next_key_lock?
实验结果:只锁住了record记录
No.2 insert单条,有主键和普通索引,是record_lock还是next_key_lock?
实验结果:只锁住了record记录
No.3 insert…values(),(),();有主键和普通索引,是record_lock还是next_key_lock?
实验结果:只锁住了record记录
update
No.4 update…set…where id=….走主键时,产生是record_lock还是next_key_lock?
实验现象,当此update语句不提交时。其它session执行update语句如果是
走主键索引:如果锁住的是Record记录,则被堵塞
普通索引:其它都不会被堵塞,除非普通索引所对应的主键是Record记录,则被堵塞
或不走索引:全被堵塞
实验结果:走主键更新时,只锁住主键记录对应的record。当id值不存在时,其它session允许update该id,但不允许insert该id
No.5 update…set…where col1=….走普通索引时,产生是record_lock还是next_key_lock?
实验现象:
mysql> select * from t1 where col1=91190;
+------+-------+-------+---------------------+
| id | col1 | col2 | col3 |
+------+-------+-------+---------------------+
| 1496 | 91190 | 98879 | 2016-06-26 01:53:42 |
+------+-------+-------+---------------------+
update t1 set col2=‘98879‘ where col1=91190;时(存在col1记录91186、91190、91197),其它session:
被堵塞:
update t1 set col2=‘98879‘ where col1=91190;
update t1 set col2=‘98879‘ where id=1496;
insert into t1 values(200012,91186,‘ok‘,‘2016-06-26 01:59:12‘);
insert into t1 values(200013,91187,‘ok‘,‘2016-06-26 01:59:12‘);
insert into t1 values(200014,91188,‘ok‘,‘2016-06-26 01:59:12‘);
insert into t1 values(200015,91189,‘ok‘,‘2016-06-26 01:59:12‘);
insert into t1 values(200016,91190,‘ok‘,‘2016-06-26 01:59:12‘);
insert into t1 values(200017,91191,‘ok‘,‘2016-06-26 01:59:12‘);
insert into t1 values(200018,91192,‘ok‘,‘2016-06-26 01:59:12‘);
insert into t1 values(200019,91193,‘ok‘,‘2016-06-26 01:59:12‘);
insert into t1 values(200020,91193,‘ok‘,‘2016-06-26 01:59:12‘);
insert into t1 values(200021,91194,‘ok‘,‘2016-06-26 01:59:12‘);
insert into t1 values(200022,91195,‘ok‘,‘2016-06-26 01:59:12‘);
insert into t1 values(200023,91196,‘ok‘,‘2016-06-26 01:59:12‘);
delete from t1 where col1=91190;
delete from t1 where id=1496;
不堵塞:
select * from t1 where col1=91191 for update;
select * from t1 where col1=91192 for update;
select * from t1 where col1=91193 for update;
select * from t1 where col1=91186 for update;
select * from t1 where col1=91187 for update;
select * from t1 where col1=91188 for update;
select * from t1 where col1=91189 for update;
insert into t1 values(200025,91185,‘ok‘,‘2016-06-26 01:59:12‘);
insert into t1 values(200026,91197,‘ok‘,‘2016-06-26 01:59:12‘);
实验结果:
当col1值存在,update…set…where col1=….走普通索引时,
对91190产生record锁,
对[91186,91190),[91191,91197)产生间隙锁,该间隙锁允许update,但不允许insert
当col1值不存在,如:mysql> update t1 set col2=‘98879‘ where col1=91189;时
对[91186,91189]加间隙锁,该间隙锁允许update,但不允许insert
对其它范围不加锁。
No.6 update…set…where id<3000….走主键时,产生是record_lock还是next_key_lock?
实验结果:
锁住的是id在 [负无穷大-3000] 中id存在记录的值;
No.7 update…set…where col1<300….走普通索引时,产生是record_lock还是next_key_lock?
锁住的是col1 in [负无穷大-300)的 next_key_lock 及记录对应主键的 record 锁
同No.5 col1的record值不允许update , 间隙内允许update,不允许insert
No.8 update…set…where col1<3000….不走col1索引时,产生是record_lock还是next_key_lock?
锁住的是col1 in [负无穷大-正无穷大] 的 next_key_lock 及记录对应主键的 record 锁
同No.5 col1的record值不允许update , 间隙内允许update,不允许insert
混合SQL
No.9 insert … select … from …where col1<3000….不走索引时,产生是record_lock还是next_key_lock?
锁住的是表t1的col1 in [负无穷大-3000)的 next_key_lock 及记录对应主键的 record 锁
同No.5 col1的record值不允许update , 间隙内允许update,不允许insert
典型死锁模拟测试
标签:
原文地址:http://www.cnblogs.com/janehoo/p/5621241.html