zoukankan      html  css  js  c++  java
  • MYSQL~锁例子阅读笔记

    内容来自阅读该文章: https://mp.weixin.qq.com/s/7BuvuRFuelBTI2rn2If6cA

    Select * from xxx where id in (xx,xx,xx) for update 在in里面的列表值mysql是会自动从小到大排序,加锁也是一条条从小到大加的锁

    Session1:
    mysql> select * from t3 where id in (8,9) for update;
    Session2:
    select * from t3 where id in (10,8,5) for update;  // 等待
    Session3:
    mysql> select * from t3 where id=5 for update;     // 等待
    Session4:
    mysql> select * from t3 where id=10 for update;

    当对存在的行进行锁的时候(主键),mysql就只有行锁。
    当对未存在的行进行锁的时候(即使条件为主键),mysql是会锁住一段范围(有gap锁)

    以id为主键为例,目前还没有id=22的行,如果表中目前有已有的id为(11 , 12),那么就锁住(12,无穷大),如果表中目前已有的id为(11 , 30),那么就锁住(11,30)
    Session1:
    select * from t3 where id=22 for update;
    Empty set (0.00 sec)
    
    session2:
    select * from t3 where id=23  for update;
    Empty set (0.00 sec)
    
    Session1:
    insert into t3 values(22,'ac','a',now());
    锁等待中……
    
    Session2:
    insert into t3 values(23,'bc','b',now());
    ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
    mysql> select * from t3 where id=9 for update;
    +----+--------+------+---------------------+
    | id | course | name | ctime               |
    +----+--------+------+---------------------+
    |  9 | JX     | f    | 2016-03-01 11:36:30 |
    +----+--------+------+---------------------+
    
    row in set (0.00 sec)
    Session2:
    mysql> select * from t3 where id<20 for update;
    锁等待中
    
    Session1:
    mysql> insert into t3 values(7,'ae','a',now());
    ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

    循环等待

    二级索引->主索引->循环等待

    CREATE TABLE dltask (
        id bigint unsigned NOT NULL AUTO_INCREMENT COMMENT ‘auto id’,
        a varchar(30) NOT NULL COMMENT ‘uniq.a’,
        b varchar(30) NOT NULL COMMENT ‘uniq.b’,
        c varchar(30) NOT NULL COMMENT ‘uniq.c’,
        x varchar(30) NOT NULL COMMENT ‘data’,   
        PRIMARY KEY (id),
        UNIQUE KEY uniq_a_b_c (a, b, c)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT=’deadlock test’;
    // a,b,c三列,组合成一个唯一索引,主键索引为id列
    delete from dltask where a=? and b=? and c=?;

    InnoDB上删除一条记录,并不是真正意义上的物理删除,而是将记录标识为删除状态。(注:这些标识为删除状态的记录,后续会由后台的Purge操作进行回收,物理删除。但是,删除状态的记录会在索引中存放一段时间。) 在RR隔离级别下,唯一索引上满足查询条件,但是却是删除记录,如何加锁?InnoDB在此处的处理策略与前两种策略均不相同,或者说是前两种策略的组合:对于满足条件的删除记录,InnoDB会在记录上加next key lock X(对记录本身加X锁,同时锁住记录前的GAP,防止新的满足条件的记录插入。) Unique查询,三种情况,对应三种加锁策略,总结如下:

    此处,我们看到了next key锁,是否很眼熟?对了,前面死锁中事务1,事务2处于等待状态的锁,均为next key锁。明白了这三个加锁策略,其实构造一定的并发场景,死锁的原因已经呼之欲出。但是,还有一个前提策略需要介绍,那就是InnoDB内部采用的死锁预防策略。

    • 找到满足条件的记录,并且记录有效,则对记录加X锁,No Gap锁(lock_mode X locks rec but not gap);

    • 找到满足条件的记录,但是记录无效(标识为删除的记录),则对记录加next key锁(同时锁住记录本身,以及记录之前的Gap:lock_mode X);

    • 未找到满足条件的记录,则对第一个不满足条件的记录加Gap锁,保证没有满足条件的记录插入(locks gap before rec);

    InnoDB引擎内部(或者说是所有的数据库内部),有多种锁类型:事务锁(行锁、表锁)Mutex(保护内部的共享变量操作)RWLock(又称之为Latch,保护内部的页面读取与修改)

    InnoDB每个页面为16K,读取一个页面时,需要对页面加S锁,更新一个页面时,需要对页面加上X锁。任何情况下,操作一个页面,都会对页面加锁,页面锁加上之后,页面内存储的索引记录才不会被并发修改。

    因此,为了修改一条记录,InnoDB内部如何处理:
    • 根据给定的查询条件,找到对应的记录所在页面;

    • 对页面加上X锁(RWLock),然后在页面内寻找满足条件的记录;

    • 在持有页面锁的情况下,对满足条件的记录加事务锁(行锁:根据记录是否满足查询条件,记录是否已经被删除,分别对应于上面提到的3种加锁策略之一);

    死锁预防策略:相对于事务锁,页面锁是一个短期持有的锁,而事务锁(行锁、表锁)是长期持有的锁。因此,为了防止页面锁与事务锁之间产生死锁。InnoDB做了死锁预防的策略:持有事务锁(行锁、表锁),可以等待获取页面锁;但反之,持有页面锁,不能等待持有事务锁。

    根据死锁预防策略,在持有页面锁,加行锁的时候,如果行锁需要等待。则释放页面锁,然后等待行锁。此时,行锁获取没有任何锁保护,因此加上行锁之后,记录可能已经被并发修改。因此,此时要重新加回页面锁,重新判断记录的状态,重新在页面锁的保护下,对记录加锁。如果此时记录未被并发修改,那么第二次加锁能够很快完成,因为已经持有了相同模式的锁。但是,如果记录已经被并发修改,那么,就有可能导致本文前面提到的死锁问题。

    首先,假设dltask中只有一条记录:(1, ‘a’, ‘b’, ‘c’, ‘data’)。三个并发事务,同时执行以下的这条SQL:delete from dltask where a=’a’ and b=’b’ and c=’c’;

    并且产生了以下的并发执行逻辑,就会产生死锁:

  • 相关阅读:
    模拟登陆江西理工大学教务系统
    python3爬虫 -----华东交大校园新闻爬取与数据分析
    以selenium模拟登陆12306
    PAT (Basic Level) Practice (中文)1076 Wifi密码 (15 分)
    PAT (Basic Level) Practice (中文)1047 编程团体赛 (20 分)
    PAT (Basic Level) Practice (中文)1029 旧键盘 (20 分)
    PAT (Basic Level) Practice (中文)1016 部分A+B (15 分)
    PAT (Basic Level) Practice (中文)1031 查验身份证 (15 分)
    PAT (Basic Level) Practice (中文)1041 考试座位号 (15 分)
    PAT (Basic Level) Practice (中文)1037 在霍格沃茨找零钱 (20 分)
  • 原文地址:https://www.cnblogs.com/it-worker365/p/14626718.html
Copyright © 2011-2022 走看看