mysql - 镜像表 : triggers, 死锁和隐式提交

标签 mysql stored-procedures triggers deadlock autocommit

我有 2 个相似的表,例如 A 和 B。我想将 A 中的插入复制到 B,并将 B 中的插入复制到 A 以集成两个用户系统。我在每一个上都配置了“插入触发器后”。示例:

DELIMITER $$
CREATE DEFINER = `root`@`localhost` TRIGGER
`after_A_INSERT`
AFTER INSERT ON `A`
FOR EACH ROW BEGIN 
INSERT INTO `B`
SET `id` = NEW.`id`,`name` = NEW.`name`;
END$$
DELIMITER ;

DELIMITER $$
CREATE DEFINER = `root`@`localhost` TRIGGER
`after_B_INSERT`
AFTER INSERT ON `B`
FOR EACH ROW BEGIN 
INSERT INTO `A`
SET `id` = NEW.`id`,`name` = NEW.`name`;
END$$
DELIMITER ;

如果我在 A 中插入,触发器会调用 B 中的插入,但此插入会在 B 中执行触发器,并且会发生死锁,从而避免无限循环。

我尝试编辑触发器以在执行 INSERT 之前删除另一个表触发器,然后在它之后再次创建它。示例:

DELIMITER $$
CREATE DEFINER = `root`@`localhost` TRIGGER
`after_B_INSERT`
AFTER INSERT ON `B`
FOR EACH ROW BEGIN 
DROP TRIGGER IF EXISTS `after_A_INSERT`;
INSERT INTO `A`
SET `id` = NEW.`id`, `name` = NEW.`name`;
/* And CREATE again here */
END$$
DELIMITER ;

但是 CREATE 是一种数据定义语言 (DDL) 语句,它会进行隐式提交。因此,这是不可能的。

我曾尝试调用一个内部包含 DROP 的过程来显式处理提交,但也不可能。

对镜像这 2 个表有什么建议吗?


更新:使用 Bill Karwin suggestion ,我向每个表添加了一个 origin 字段,每个表都有各自的默认值 AB。然后,我按如下方式更改(DROP 和 reCREATE)触发器:

A 中的触发器:

...
BEGIN 
IF NEW.`origin`='A' THEN
    INSERT INTO `B`
        SET `id` = NEW.`id`, `name` = NEW.`name`,  `origin` = NEW.`origin`;
    END IF;
END

B 中的触发器:

...
BEGIN 
IF NEW.`origin`='B' THEN
    INSERT INTO `A`
        SET `id` = NEW.`id`, `name` = NEW.`name`, `origin` = NEW.`origin`;
    END IF;
END

最佳答案

您需要一些方法来避免产生循环。

我建议在两个表中添加一列 origin。在表 A 中,设置 DEFAULT 'A'。在表 B 中,设置 DEFAULT 'B'

在您的应用程序中向任一表插入时,始终省略 origin 列,使其采用默认值。

在两个触发器中,仅当 NEW.origin 等于相应表的默认值时才复制到另一个表。


关于您的评论和新错误:

sorry,忘记说了,在trigger中插入其他表的时候,还必须复制NEW.origin的值。就在您的应用程序中,当您执行原始插入时,您是否省略了 origin

A 中的触发器:

...
BEGIN 
IF NEW.`origin`='A' THEN
    INSERT INTO `B`
        SET `id` = NEW.`id`, `name` = NEW.`name`, `origin` = NEW.`origin`;
    END IF;
END

B 中的触发器:

...
BEGIN 
IF NEW.`origin`='B' THEN
    INSERT INTO `A`
        SET `id` = NEW.`id`, `name` = NEW.`name`, `origin` = NEW.`origin`;
    END IF;
END

我创建了这些触发器然后进行了测试:

mysql> insert into A set name = 'bill';
Query OK, 1 row affected (0.00 sec)

mysql> insert into B set name = 'john';
Query OK, 1 row affected (0.01 sec)

mysql> select * from A;
+----+------+--------+
| id | name | origin |
+----+------+--------+
|  1 | bill | A      |
|  2 | john | B      |
+----+------+--------+
2 rows in set (0.00 sec)

mysql> select * from B;
+----+------+--------+
| id | name | origin |
+----+------+--------+
|  1 | bill | A      |
|  2 | john | B      |
+----+------+--------+

关于mysql - 镜像表 : triggers, 死锁和隐式提交,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26220377/

相关文章:

c# - C#调用存储过程

mysql - 如何在同一台服务器上复制 MySQL 数据库

PHP MySql 三级菜单速度优化

sql-server - Python - pyodbc 使用参数名称调用存储过程

sql - Oracle 错误 PLS-00323 : subprogram or cursor is declared in a package specification and must be defined in the package body

sql-server - 循环触发器内的所有列

PHP-HTML5-Form - 我的查询生成的下拉列表发布了一个空白值

php - 可以在不实例化新对象的情况下重新打开 MYSQLI 连接吗

c# - c#中图像的条件显示

javascript - command/comply、listento/trigger、request/reply 之间的 Marionette 区别