镜像表:触发器,死锁和隐式提交

时间:2014-10-06 16:14:03

标签: mysql stored-procedures triggers deadlock autocommit

我有两个类似的表,例如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之前编辑触发器以DROP另一个表触发器,然后在它之后再次创建它。例如:

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调用一个PROCEDURE来明确处理提交,但也不可能。

是否有任何反映这两张桌子的建议?


更新:使用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

1 个答案:

答案 0 :(得分:3)

你需要一些方法来避免创建一个循环。

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

在应用程序中的任何一个表中插入时,请始终省略origin列,允许其使用默认值。

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


重新发表评论和新错误:

抱歉,我忘了在插入另一个表时触发器中,你还必须复制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      |
+----+------+--------+