【发布时间】:2020-02-26 12:01:33
【问题描述】:
我发现两个用户同时执行函数时会出现 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;
审计表
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 中选择最大 id 并将记录插入到 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 代码中包含的事务
- 从 PHP 代码中删除 $this->insertRecord('audit_table'); 行
- 修改触发器,使其没有来自 audit_table 的 select 语句
我想知道此问题的根本原因。另一个事务在触发时是否从 MySQL 触发器开始?触发器中的事务和锁是如何工作的?
我发现以下两个问题也与一个类似的问题有关。
【问题讨论】:
标签: mysql concurrency triggers transactions innodb