Mysql间隙锁定/下一键锁定的规则

时间:2018-09-19 06:17:38

标签: mysql locking

我不确定为什么会发生以下行为。我认为它必须与差距锁定/下一键锁定有关。文档中提到了它们,但解释不详细。

-- isolation level is Repeatable Read
-- create the table
create table t (id int primary key auto_increment, COL1 int, key idx_a(COL1));
insert into t (COL1) values(5), (10), (11), (13), (20);
select * from t;
----   ----
 id  |  COL1
----   ----
 1   |  5
 2   |  10
 3   |  11
 4   |  13
 5   |  20

-- in transaction 1
select * from t where COL1 = 13 for update;
-- in transaction 2
insert into t (COL1) values(10); -- success
insert into t (COL1) values(11); -- blocks
insert into t (COL1) values(12); -- blocks
.
.
insert into t (COL1) values(19); -- blocks
insert into t (COL1) values(20); -- success
-- in transaction 3
update t set COL1 = 11 where COL1 = 10; -- success
update t set COL1 = 12 where COL1 = 10; -- blocks
.
.
update t set COL1 = 20 where COL1 = 10; -- blocks
update t set a = 21 where a = 10; -- success

看来:

  1. COL1的INSERT锁定,其值为[11,20)(11到20,不包括20)

  2. COL1的更新锁定为(11,20]中的值(11到20,不包括11)

我想知道为什么MySQL这样表现?这种锁定的一般规则是什么?

3 个答案:

答案 0 :(得分:0)

根据MySQL 5.7 InnoDB可重复读取
由于COL1具有非唯一索引,
select * from t where COL1 = 13 for update;
该语句锁定id = 4的集群索引B + Tree记录,还锁定具有COL1 = 10的记录的COL1索引B + Tree,并锁定(k = 11,id = 3的COL1索引B + Tree )到(k = 20,id = 5)并带有间隙锁定。 insert into t (COL1) values(10); equals to : insert into t (id, COL1) values(6,10); gap lock insert into t (COL1) values(11); equals to : insert into t (id, COL1) values(7,11); gap lock insert into t (COL1) values(12); equals to : insert into t (id, COL1) values(8,12); gap lock insert into t (COL1) values(19); gap lock insert into t (COL1) values(20); equals to : insert into t (id, COL1) values(9,20);

但请参阅以下条件:
CREATE TABLE `t` ( `id` int(11) NOT NULL, `k` int(11) DEFAULT NULL, PRIMARY KEY (`id`), KEY `idx_k` (`k`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8
insert into t values(2,2),(6,6);
然后插入:
1, insert into t values (1,2); success 2, insert into t values (3,2); block

3, insert into t values (5,6); block 4, insert into t values (7,6); success 它们是否都可以在k'B + Tree中插入这些值的位置? enter image description here

因此您可以看到(k = 2,id = 1)可以插入,因为它不在间隙中,还可以插入值(k = 6,id = 7),(k = 2,id = 3)和( k = 6,id = 5)无法插入,因为它们在间隙中。

答案 1 :(得分:0)

select * from t where COL1 = 13 for update; 

此sql子句将锁定范围:

((11,3), (13,4)]
((13,4), (20,5)]

所以,我将在您的交易2和3中说明结果

insert into t (COL1) values(10); -- success because (10, 6) not in the gap range.

insert into t (COL1) values(11); -- block   because (11, 7) in the gap range.

insert into t (COL1) values(12); -- block   because (12, 8) in the gap range.

insert into t (COL1) values(19); -- block   because (19, 9) in the gap range.

insert into t (COL1) values(20); -- success because (20, 10) not in the gap range.

update t set COL1 = 11 where COL1 = 10; --success because (11,2) not in the gap range.

update t set COL1 = 12 where COL1 = 10; -- blocks because (12,2) in the gap range.

update t set COL1 = 20 where COL1 = 10; -- blocks because (20,2) in the gap range.

update t set COL1 = 21 where COL1 = 10; -- success because (21,2) not in the gap range. 

答案 2 :(得分:0)

执行后

create table t (id int primary key auto_increment, COL1 int, key idx_a(COL1));
insert into t (COL1) values(5), (10), (11), (13), (20);

-- transaction 1
start transaction;
select * from t where COL1 = 13 for update;

select * from performance_schema.data_locks的输出是:

+--------+----------------------------------------+-----------------------+-----------+----------+---------------+-------------+----------------+-------------------+------------+-----------------------+-----------+---------------+-------------+-----------+
| ENGINE | ENGINE_LOCK_ID                         | ENGINE_TRANSACTION_ID | THREAD_ID | EVENT_ID | OBJECT_SCHEMA | OBJECT_NAME | PARTITION_NAME | SUBPARTITION_NAME | INDEX_NAME | OBJECT_INSTANCE_BEGIN | LOCK_TYPE | LOCK_MODE     | LOCK_STATUS | LOCK_DATA |
+--------+----------------------------------------+-----------------------+-----------+----------+---------------+-------------+----------------+-------------------+------------+-----------------------+-----------+---------------+-------------+-----------+
| INNODB | 140043377180872:1075:140043381460688   |                  2368 |        49 |      180 | test          | t           | NULL           | NULL              | NULL       |       140043381460688 | TABLE     | IX            | GRANTED     | NULL      |
| INNODB | 140043377180872:14:5:5:140043381457776 |                  2368 |        49 |      180 | test          | t           | NULL           | NULL              | idx_a      |       140043381457776 | RECORD    | X             | GRANTED     | 13, 4     |
| INNODB | 140043377180872:14:4:5:140043381458120 |                  2368 |        49 |      180 | test          | t           | NULL           | NULL              | PRIMARY    |       140043381458120 | RECORD    | X,REC_NOT_GAP | GRANTED     | 4         |
| INNODB | 140043377180872:14:5:6:140043381458464 |                  2368 |        49 |      180 | test          | t           | NULL           | NULL              | idx_a      |       140043381458464 | RECORD    | X,GAP         | GRANTED     | 20, 5     |
+--------+----------------------------------------+-----------------------+-----------+----------+---------------+-------------+----------------+-------------------+------------+-----------------------+-----------+---------------+-------------+-----------+

事务1持有下一键锁定((11,3),(13,4)]和间隙锁定((13,4),(20,5))。

insert into t (COL1) values(10)insert into t (COL1) values(20)等于insert into t (COL1, id) values(10, ?),并且?必须大于5,因此(10,?)和(20,?)都不在((11,3),(13,4)]或((13,4),(20,5)),这就是它们能够成功的原因。insert into t (COL1) values(11)insert into t (COL1) values(19),它们位于( (11,3),(13,4)]或((13,4),(20,5)),这就是它们被阻止的原因。

更新就像删除然后插入。 update t set COL1 = 11 where COL1 = 10将插入((11,2),(11,2)不在((11,3),(13,4)]或((13,4),(20,5))中,即update t set COL1 = 12 where COL1 = 10update t set COL1 = 20 where COL1 = 10将插入(?,2),而?在[12,20]中,所以(?,2)在((11,3)中,(13,4)]或((13,4),(20,5)),这就是它们被阻止的原因。我认为update t set a = 21 where a = 10应该为update t set COL1 = 21 where COL1 = 10,它将插入(21,2 ),(21,2)不在((11,3),(13,4)]或((13,4),(20,5))中,这就是它成功的原因。