MySQL: INSERT 被外键引用行的 UPDATE 阻塞
MySQL: INSERT blocked by an UPDATE of the foreign key referenced row
让我用一个 SQL 例子开始我的问题。
这是 table 设置:
- 创建 table
x
和 y
。带y.x
指的是x.id
.
- 在
x
(id=1) 中插入一行。
START TRANSACTION;
CREATE TABLE `x` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`value` INT(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB;
CREATE TABLE `y` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`x_id` INT(11) NOT NULL,
`value` INT(11) NOT NULL,
PRIMARY KEY (`id`),
CONSTRAINT `fk_x` FOREIGN KEY (`x_id`)
REFERENCES `x` (`id`)
) ENGINE=INNODB;
INSERT INTO x values (1,123456);
COMMIT;
现在启动事务 (Trx A) 以更新 x
中的行。
START TRANSACTION;
UPDATE x SET value=value+1 WHERE id = 1;
在提交之前,我正在启动另一个事务 (Trx B) 以向 y
.
插入一行
START TRANSACTION;
INSERT INTO y VALUES (null,1,123456);
---- HANGED ----
-- Until Trx A is committed or rolled-back, the Trx B is hanged here.
问题是 - Trx B 是否会在此时被挂起?为什么以及有什么解决方法?
This has been tested on MySQL 5.7.21, Percona 5.7.21, MariaDB 10.2.14
是的,这是预期的。
Trx A 在记录上有排它锁 (X),因为它正在更新它。
Trx B 必须在所有外键引用上获取共享模式 (S) 锁,以确保满足约束条件。它等待 Trx A 释放它的 X 锁。
无法避免这种情况并保持参照完整性。如果您设法禁用锁定,MySQL 将无法保证引用的行存在。
通常的解决方法是删除外键。
让我用一个 SQL 例子开始我的问题。
这是 table 设置:
- 创建 table
x
和y
。带y.x
指的是x.id
. - 在
x
(id=1) 中插入一行。
START TRANSACTION;
CREATE TABLE `x` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`value` INT(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB;
CREATE TABLE `y` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`x_id` INT(11) NOT NULL,
`value` INT(11) NOT NULL,
PRIMARY KEY (`id`),
CONSTRAINT `fk_x` FOREIGN KEY (`x_id`)
REFERENCES `x` (`id`)
) ENGINE=INNODB;
INSERT INTO x values (1,123456);
COMMIT;
现在启动事务 (Trx A) 以更新 x
中的行。
START TRANSACTION;
UPDATE x SET value=value+1 WHERE id = 1;
在提交之前,我正在启动另一个事务 (Trx B) 以向 y
.
START TRANSACTION;
INSERT INTO y VALUES (null,1,123456);
---- HANGED ----
-- Until Trx A is committed or rolled-back, the Trx B is hanged here.
问题是 - Trx B 是否会在此时被挂起?为什么以及有什么解决方法?
This has been tested on MySQL 5.7.21, Percona 5.7.21, MariaDB 10.2.14
是的,这是预期的。
Trx A 在记录上有排它锁 (X),因为它正在更新它。
Trx B 必须在所有外键引用上获取共享模式 (S) 锁,以确保满足约束条件。它等待 Trx A 释放它的 X 锁。
无法避免这种情况并保持参照完整性。如果您设法禁用锁定,MySQL 将无法保证引用的行存在。
通常的解决方法是删除外键。