FOR UPDATE with IN子句导致LOCK WAIT TIMEOUT

时间:2014-12-29 14:25:23

标签: mysql transactions locking mariadb

使用SELECT ... FOR UPDATE语句时,我遇到了LOCK WAIT TIMEOUT问题。

我准备了我不理解的场景。你能告诉我为什么前三个块立即被执行,但是最后一个块等了吗?

感谢。

-- I'm using MariaDb

-- T1 is the mysql terminal window 1
-- T2 is the mysql terminal window 2

CREATE TABLE `test` (
  `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `name` VARCHAR(255) NOT NULL
) COMMENT='' ENGINE='InnoDB' COLLATE 'utf8_bin';

INSERT INTO test SET name='foo';

T2: START TRANSACTION;
T1: START TRANSACTION;
T1: SELECT * FROM test WHERE id IN (1) FOR UPDATE;
T2: INSERT INTO test SET name='foo'; -- executed immediately

T2: START TRANSACTION;
T1: START TRANSACTION;
T1: SELECT * FROM test WHERE id IN (1,2) FOR UPDATE;
T2: INSERT INTO test SET name='foo'; -- executed immediately

T2: START TRANSACTION;
T1: START TRANSACTION;
T1: SELECT * FROM test WHERE id IN (1,2,3) FOR UPDATE;
T2: INSERT INTO test SET name='foo'; -- executed immediately

T2: START TRANSACTION;
T1: START TRANSACTION;
T1: SELECT * FROM test WHERE id IN (1,2,3,4) FOR UPDATE;
T2: INSERT INTO test SET name='foo'; -- waits for T1 to commit

T2: commit;
T1: commit;

2 个答案:

答案 0 :(得分:1)

InnoDB行级锁是index-locks in reality。记录较少的特性 * 是:如果锁定SELECT没有(或不能)使用(用户定义的)索引,那么只能使用默认的聚簇索引,并且整个桌子被锁定了。

优化器很可能决定索引对于检查" long" IN()参数列表(可能因为需要扫描大部分表)。这会导致您检测到意外的副作用。

可以通过查看execution plan来确认此假设。

答案 1 :(得分:0)

我认为您假设“select for update”仅锁定UPDATE的行。但是,锁定也适用于INSERT,因为插入可以插入属于原始“select”的记录。该文档声明它“锁定行和任何相关的索引条目”。

http://dev.mysql.com/doc/refman/5.6/en/innodb-locking-reads.html