我不知道为什么会发生以下行为。我想这一定和空档锁/下一把钥匙锁有关。文件提到了他们,但解释不详细。
-- 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
看来:
值在[11,20]中的col1的insert被锁定(11到20,排除20)
值为(11,20)的列1的更新被锁定(11到20,排除11)
我想知道mysql为什么会这样?这种锁的一般规则是什么?
3条答案
按热度按时间iklwldmw1#
执行后
输出
select * from performance_schema.data_locks
是:事务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 = 10
至update 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)),这就是它成功的原因。g52tjvyc2#
MySQL5.7下innodb可重复读取
因为col1有一个非空索引,
select * from t where COL1 = 13 for update;
语句锁定id=4的集群索引b+树记录,也锁定col1=10的记录所在的col1索引b+树,并使用gap lock将col1索引b+树从(k=11,id=3)锁定到(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 lockinsert into t (COL1) values(12); equals to : insert into t (id, COL1) values(8,12); gap lock
insert into t (COL1) values(19); gap lockinsert into t (COL1) values(20); equals to : insert into t (id, COL1) values(9,20);
但看看这个条件:CREATE TABLE
t(
idint(11) NOT NULL,
kint(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); block4, insert into t values (7,6); success
如果它们都能插入这些值在k'b+树中的位置在哪里?所以你可以看到(k=2,id=1)可以插入,因为它不在间隙中,同样值(k=6,id=7),(k=2,id=3)和(k=6,id=5)不能插入,因为它们在间隙中。
y3bcpkx13#
此sql子句将锁定范围:
所以,我会在你的交易2和交易3中解释结果