Я обнаружил проблему взаимоблокировки SQL, которая возникает, когда функция выполняется одновременно двумя пользователями. У меня есть функция PHP, которая выполняет несколько запросов на вставку базы данных, которые заключают в транзакции. И одна из вставок также запускает курок. См. Мою схему таблицы и пример кода ниже.
main_table
CREATE TABLE `main_table` (
`id` INT NOT NULL AUTO_INCREMENT,
`action_time` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
history_table
CREATE TABLE `history_table` (
`id` INT NOT NULL AUTO_INCREMENT,
`action_time` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
`audit_id` INT,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
aud_table
CREATE TABLE `audit_table` (
`id` INT NOT NULL AUTO_INCREMENT,
`action_time` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
У меня есть триггер на main_table , определенный следующим образом. То, что он делает, - это выбор максимального идентификатора из audit_table и вставка записи в history_table .
CREATE TRIGGER watch_insert_main_table
AFTER INSERT ON main_table
FOR EACH ROW BEGIN
DECLARE max_id INT;
SET max_id = (SELECT MAX(`id`) FROM `audit_table`) + 1;
INSERT INTO `history_table` SET audit_id=max_id;
END;
Ниже приведена функция, которая выполняется двумя пользователямиодновременно. insertRecord Функция просто вставляет запись в данную таблицу.
try {
$dbConnection->beginTransaction();
$this->insertRecord('main_table');
$this->insertRecord('audit_table');
$dbConnection->commit();
} catch (Exception $e) {
$dbConnection->rollback();
}
Я получаю следующую ошибку мертвой блокировки, когда функция вызывается во второй раз (одновременно).
40001 - SQLSTATE[40001]: Serialization failure: 1213 Deadlock found when trying to get lock; try restarting transaction
Если я внесу одно из следующих изменений, эта проблема не возникнет.
- Удалите вложенную транзакцию в коде PHP
- Удалите $ this-> insertRecord ('audit_table'); строка из кода PHP
- Измените триггер так, чтобы в нем не было оператора select из aud_table
Я хочузнать коренную причину этой проблемы . Другая транзакция запускается из триггера MySQL при запуске? Как транзакции и блокировки работают внутри триггера?
Я обнаружил, что следующие два вопроса также связаны с похожей проблемой.