码迷,mamicode.com
首页 > 数据库 > 详细

各种SQL加锁

时间:2016-06-28 20:11:49      阅读:194      评论:0      收藏:0      [点我收藏+]

标签:

今天上午和同事火热争论了一番,争来争去围绕的就锁的几个基本概念。

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

典型死锁模拟测试

 

各种SQL加锁

标签:

原文地址:http://www.cnblogs.com/janehoo/p/5621241.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!