美文网首页
MySQL Next-Key Lock边界值问题

MySQL Next-Key Lock边界值问题

作者: c7d122ec46c0 | 来源:发表于2020-07-11 20:49 被阅读0次

    Next-Key Lock

    A next-key lock is a combination of a record lock on the index record and a gap lock on the gap before the index record.

    next-key lock 就是gap lock加record lock
    mysql官网的例子
    官网
    假设索引有10,11,13,20,next-key lock的范围是

    (negative infinity, 10]
    (10, 11]
    (11, 13]
    (13, 20]
    (20, positive infinity)

    重点是要考虑的边界为什么是左开右闭区间

    例子

    前提,next-key lock 只有在rr级别,且非唯一索引的情况下才会生效,以下操作的mysql 版本是5.7.21

    例子1

    非唯一索引id,没有自定义主键

    CREATE TABLE `lock1` (
      `id` int(11) unsigned NOT NULL,
      KEY `idx_union1` (`id`) USING BTREE
    ) ENGINE=InnoDB  DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
    
    insert into lock1 VALUES (1),(2),(3),(4),(5);
    
    //  开始事务,当前读id 为2 的记录,锁定范围应该是(1,3]
    session1
    
    start TRANSACTION;
    
    SELECT * from lock1 WHERE id = 2 for UPDATE;
    
    //  
    session2
    insert into lock1 VALUES (1);  //  Lock wait timeout exceeded; try restarting transaction 事务超时
    insert into lock1 VALUES (3); // 执行成功
    

    第一个例子不符合官网描述,3没有被锁定,1被锁定

    例子2

    锁定范围应该是(1,5]
    非唯一索引id,自定义唯一索引pid

    CREATE TABLE `lock3` (
      `id` int(11) unsigned NOT NULL,
      `pid` int(11) unsigned NOT NULL,
      KEY `idx_union1` (`id`) USING BTREE,
      PRIMARY key (`pid`)
    ) ENGINE=InnoDB  DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
    
    insert into lock3 VALUES (1,10),(1,11),(3,12),(3,19),(5,22),(5,30);
    
    //session1
    start TRANSACTION;
    SELECT * from lock3 WHERE id = 3 for UPDATE;
    //session2 
    insert into lock3 VALUES (1,3); // 成功
    insert into lock3 VALUES (5,21); // 失败
    

    第二个例子看起来像是(1,5]这个范围

    原因

    最根本的原因是gaplock 的范围是跟主键索引相关的
    第一个例子lock1表没有设置主键,但mysql实际会生成自增默认聚簇索引

    If the table has no PRIMARY KEY or suitable UNIQUE index, InnoDB internally generates a hidden clustered index named GEN_CLUST_INDEX on a synthetic column containing row ID values. The rows are ordered by the ID that InnoDB assigns to the rows in such a table. The row ID is a 6-byte field that increases monotonically as new rows are inserted. Thus, the rows ordered by the row ID are physically in insertion order

    我们假设它叫pid,假设自增从1开始 那lock1的实际数据应该是(1,1),(2,2),(3,3),(4,4),(5,5),这样只是为了便于理解。因为InnoDB索引结构都是B+树,索引记录都是按顺序排序的,要再插入一条id=2的记录,其必定只能是在(pid=1,id=1)-(pid=3,id=3)记录之间插入,为了防止幻读,就会在这段加锁,假如让1新增成功,则必定在(pid=1,id=1)-(pid=3,id=3)之间,所以新增失败。对于新增3这条记录,由于主键自增,新增的记录应该是(3,6)这样,并不在(pid=1,id=1)-(pid=3,id=3)之间
    第二个例子
    锁定的范围为(1,11)~(5,22),(1,3)不在这个范围之内,(5,21)在这个范围内。

    相关文章

      网友评论

          本文标题:MySQL Next-Key Lock边界值问题

          本文链接:https://www.haomeiwen.com/subject/qjricktx.html