MySQL: INSERT заблокирован UPDATE строки, на которую ссылается внешний ключ

0

Позвольте мне начать свой вопрос с примера SQL...

Вот настройка таблицы,

  1. Создайте таблицу X и Y. С yx называется x.id.
  2. Вставьте строку в 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 будет повешен в этой точке? Почему и каким-то образом обходным путем?

Это было протестировано на MySQL 5.7.21, Precona 5.7.21, Mariadb 10.2.14

Теги:
foreign-keys
innodb
rowlocking

1 ответ

0
Лучший ответ

Да, ожидается.

Trx A имеет исключительную блокировку (X) в записи, потому что она обновляет ее.

Trx B должен получить блокировку общего режима (S) для всех внешних ключей, чтобы гарантировать, что ограничения выполнены. Он ожидает, что Trx A освободит свой X-замок.

Невозможно избежать этого и сохранить ссылочную целостность. Если вам удастся отключить блокировку, MySQL не сможет гарантировать, что указанная строка существует.

Обычным обходным решением является удаление внешних ключей.

  • 0
    вздох - печально это знать, но спасибо. Я думал, что обновление ключа не приведет к тому, что это произойдет.
  • 0
    Что значит "не обновлять ключ"
Показать ещё 3 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню