• MySQL: 锁


    一、table

    CREATE TABLE `dog` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `age` int(11) DEFAULT NULL,
      `weight` int(11) DEFAULT NULL,
      PRIMARY KEY (`id`),
      KEY `idx_age` (`age`)
    ) ENGINE=InnoDB AUTO_INCREMENT=51 DEFAULT CHARSET=utf8
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    二、插入数据:
    在这里插入图片描述
    三、主键上锁的测试(唯一索引和主键情况完全相同)
    打开两个navicat窗口,分别执行set autocommit=0关闭自动提交。
    1.在两个窗口分别执行:

    select * from dog where id=35 lock in share mode;  
    
    • 1

    都不会阻塞。

    2.一个窗口执行:

    select * from dog where id=35 lock in share mode;  
    
    • 1

    另一个窗口执行:

    select * from dog where id=35 for update;
    
    • 1

    则第二个窗口报:Lock wait timeout exceeded; try restarting transaction
    3.一个窗口执行:

    select * from dog where id=35 lock in share mode;  
    
    • 1

    另一个窗口执行:

    update dog set weight=1111 where id=35;
    
    • 1

    则第二个窗口报:Lock wait timeout exceeded; try restarting transaction

    结论:在主键上进行等值查询时,如果记录存在,则只会在记录上加记录锁。

    4.一个窗口执行:

    select * from dog where id=38 lock in share mode;  
    
    • 1

    id为38的记录并不存在
    另一个窗口执行:

    update dog set weight=1111 where id=40;
    
    • 1

    可以更新成功,但如果:

    insert into dog(id,age,weight) values(37,8,32);
    insert into dog(id,age,weight) values(39,8,32);
    
    
    
    • 1
    • 2
    • 3
    • 4

    都会阻塞
    结论:在主键上进行等值查询时,如果记录不存在,则只会把记录所在的区间右闭去掉,也就是加间隙锁,例如本例中,临键锁为(35,40],则实际加的为间隙锁(35,40)

    5.一个窗口执行:

    select * from dog where id>34 and id<40 lock in share mode;  
    
    • 1

    另一个窗口执行:

    insert into dog(id,age,weight) values(32,8,32);
    
    
    • 1
    • 2

    执行成功。
    另一个窗口如果执行:

    insert into dog(id,age,weight) values(38,8,32);
    
    
    • 1
    • 2

    阻塞
    结论:上述第一个查询,开始要经历2个间隙锁(30,35],(35,40]. 因为id>34这个条件命中了id=35这条记录,所以第一个间隙锁退化为记录锁,只锁定了id=35这条记录。因为id<40这个条件没有命中(35,40]这个临键锁的记录,所以临键锁退化为间隙锁(35,40),所以最终锁定的区间为[35,40),所以可以插入id 为32的数据,无法插入id为38的记录

    四、普通索引上锁的测试:
    1.一个窗口执行:

    select * from dog where age=20 for update;
    
    
    • 1
    • 2

    另一个窗口执行:

    insert into dog(id,age,weight) values(84,17,32);
    
    insert into dog(id,age,weight) values(85,23,32);
    
    
    • 1
    • 2
    • 3
    • 4

    都阻塞。
    结论:普通索引,等值查询且记录存在时,会给记录所在的区间加临键锁,同时给其下一个临键锁区间上加间隙锁。上述第一个查询,首先会给(10,20]这个区间加临键锁,然后给(20,30)这个区间加间隙锁。因此,锁定的区间为(10,30),如下的语句将不会阻塞:

    update dog set weight=3 where id=10;
    
    update dog set weight=3 where id=30;
    insert into dog(id,age,weight) values(85,7,32);
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2.一个窗口执行:

    select * from dog where age=43 for update;
    
    
    • 1
    • 2

    age为43的记录不存在。
    锁定的为(40,50)这个开区间
    另一个窗口执行:

    update dog set weight=3 where id=40;
    
    update dog set weight=3 where id=50;
    
    • 1
    • 2
    • 3

    都执行成功。如果执行如下语句将阻塞

    insert into dog(id,age,weight) values(86,42,32);
    insert into dog(id,age,weight) values(86,45,32);
    
    • 1
    • 2

    结论:普通索引,等值查询,记录不存在时,锁定记录所在的开区间

    3.一个窗口执行:

    select * from dog where age>44 and age< 48 for update;
    
    
    • 1
    • 2

    另一个窗口执行:

    insert into dog(id,age,weight) values(86,42,32);
    insert into dog(id,age,weight) values(86,49,32);
    
    
    • 1
    • 2
    • 3

    将阻塞。执行如下语句:

    update dog set weight=6 where id=50;
    
    
    • 1
    • 2

    成功。
    分析:上述第一条语句锁定的是(40,50)这个开区间,也就是加了间隙锁。
    如果将第一条语句改为:

    select * from dog where age>23 and age<= 30 for update;
    
    • 1

    另一个窗口执行:

    insert into dog(id,age,weight) values(86,22,32);
    
    insert into dog(id,age,weight) values(86,33,32);
    
    
    • 1
    • 2
    • 3
    • 4

    都会阻塞
    执行如下语句:

    update dog set weight=35 where id=35;
    
    
    • 1
    • 2

    将执行成功。
    分析:上述第一条语句锁定的是(20,30]这个区间和(30,35)这个区间,也就是最总锁定(20,35)这个区间。

    五、没有索引的列上锁的测试:
    1.一个窗口执行:

    select * from dog where weight=3 for update;
    
    
    • 1
    • 2

    另一个窗口执行:

    insert into dog(id,age,weight) values(99,99,99);
    
    
    • 1
    • 2

    则第二个窗口报:Lock wait timeout exceeded; try restarting transaction
    2.一个窗口执行:

    select * from dog where weight=34 for update;
    
    
    • 1
    • 2

    另一个窗口执行:

    insert into dog(id,age,weight) values(99,99,99);
    
    
    • 1
    • 2

    则第二个窗口报:Lock wait timeout exceeded; try restarting transaction

    3.一个窗口执行:

    select * from dog where weight>5 for update;
    
    
    • 1
    • 2

    另一个窗口执行:

    insert into dog(id,age,weight) values(1,1,1);
    
    
    • 1
    • 2

    则第二个窗口报:Lock wait timeout exceeded; try restarting transaction

    结论:当在没有索引的列进行锁定时,不管是等值查询查到了数据、等值查询没有查到数据、范围查询,都给相当于整个表加了表锁,其它事务无法对表进行任何插入或更新操作。

  • 相关阅读:
    Java网关的统一异常处理
    Simlab python二次开发1-将所有缸套内表面半径加大1mm
    scanf(“%s“, filename);这里的scanf函数中,“,”逗号符号后面什么时候需要用“&”这个符号,什么时候不需要用这个“&”符号?
    C中的运算和数据类型
    verilog实现分频(奇数分频,偶数分频,且50%占空比,通用版本)
    函数式接口@FunctionalInterface
    关于高德地图2.0卡顿问题的解决方案(chrome设置+显卡设置)
    数理统计笔记5:参数估计-区间估计
    信创办公–基于WPS的Word最佳实践系列 (图文环绕方式)
    AI赋能音乐创作,人人都是音视频创作者
  • 原文地址:https://blog.csdn.net/amadeus_liu2/article/details/133036000