我可以在实际触发语句之前执行MySQL触发器吗?

时间:2017-08-25 21:56:30

标签: mysql sql

我在子表上有一个触发器,用于更新父表上的计数器。无论我CREATE TRIGGER ... BEFORE INSERT还是AFTER INSERT,触发器中的SQL总是在执行之后执行。

有没有办法强制它在之前运行?

CREATE TABLE items (
  id int(11) unsigned NOT NULL AUTO_INCREMENT,
  quantity_sold int(11) unsigned DEFAULT 0,
  PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

CREATE TABLE line_items (
  id int(11) unsigned NOT NULL AUTO_INCREMENT,
  item_id int(11) unsigned DEFAULT NULL,
  quantity int(11) unsigned DEFAULT 1,
  PRIMARY KEY (id),
  CONSTRAINT fk FOREIGN KEY (item_id) REFERENCES items (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;


INSERT INTO items (id) VALUES (1);

DROP TRIGGER IF EXISTS line_item_trigger;
delimiter $$
CREATE TRIGGER line_item_trigger BEFORE INSERT ON line_items
FOR EACH ROW
BEGIN
  UPDATE items SET quantity_sold = quantity_sold + NEW.quantity WHERE id = NEW.item_id;
END
$$

运行:

INSERT INTO line_items (item_id) VALUES (1);

...导致:

INSERT INTO line_items (item_id) VALUES (1);
UPDATE items SET quantity_sold = quantity_sold + NEW.quantity WHERE id = NEW.item_id;

我希望首先发生UPDATE

(为什么?这都是在事务中完成的,INSERT在进行外键检查时锁定items表,导致整个地方出现死锁。)

提前感谢任何见解。

2 个答案:

答案 0 :(得分:0)

CREATE TRIGGER line_item_trigger BEFORE INSERT ON line_items
FOR EACH ROW

强制执行此触发器以在插入之前调用。没有什么需要做的了。

请根据需要检查提交频率,以确保您提交交易。

答案 1 :(得分:0)

您是否有示例演示此行为?

以下示例从row_count_line_items更新items表的BEFORE TRIGGER列,计算line_items表中的行数。由于它是BEFORE TRIGGERrow_count_line_items列为零(0)(此时INSERT尚未完成):

mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)

mysql> DROP TRIGGER IF EXISTS `line_item_trigger`;
Query OK, 0 rows affected (0.00 sec)

mysql> DROP TABLE IF EXISTS `line_items`, `items`;
Query OK, 0 rows affected (0.01 sec)

mysql> CREATE TABLE IF NOT EXISTS `items` (
    ->   `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
    ->   `quantity_sold` int(11) unsigned DEFAULT 0,
    ->   `row_count_line_items` int,
    ->   PRIMARY KEY (`id`)
    -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE TABLE IF NOT EXISTS `line_items` (
    ->   `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
    ->   `item_id` int(11) unsigned DEFAULT NULL,
    ->   `quantity` int(11) unsigned DEFAULT 1,
    ->   PRIMARY KEY (`id`),
    ->   CONSTRAINT `fk` FOREIGN KEY (`item_id`) REFERENCES items (`id`)
    -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO `items` (`id`) VALUES (1);
Query OK, 1 row affected (0.01 sec)

mysql> CREATE TRIGGER `line_item_trigger` BEFORE INSERT ON `line_items`
    -> FOR EACH ROW
    ->   UPDATE `items`
    ->   SET `quantity_sold` = `quantity_sold` + NEW.`quantity`,
    ->       `row_count_line_items` = (SELECT COUNT(`id`)
    ->                                 FROM `line_items`)
    ->   WHERE `id` = NEW.`item_id`;
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO `line_items` (`item_id`) VALUES (1);
Query OK, 1 row affected (0.01 sec)

mysql> COMMIT;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT `id`, `quantity_sold`, `row_count_line_items`
    -> FROM `items`;
+----+---------------+----------------------+
| id | quantity_sold | row_count_line_items |
+----+---------------+----------------------+
|  1 |             1 |                    0 |
+----+---------------+----------------------+
1 row in set (0.00 sec)

mysql> SELECT `id`, `item_id`, `quantity`
    -> FROM `line_items`;
+----+---------+----------+
| id | item_id | quantity |
+----+---------+----------+
|  1 |       1 |        1 |
+----+---------+----------+
1 row in set (0.00 sec)

请参阅db-fiddle

如果我们将事件更改为AFTERAFTER TRIGGER),那么row_count_line_items列的值将为一(1)(因为INSERT已经完成) :

mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)

mysql> DROP TRIGGER IF EXISTS `line_item_trigger`;
Query OK, 0 rows affected (0.00 sec)

mysql> DROP TABLE IF EXISTS `line_items`, `items`;
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE TABLE IF NOT EXISTS `items` (
    ->   `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
    ->   `quantity_sold` int(11) unsigned DEFAULT 0,
    ->   `row_count_line_items` int,
    ->   PRIMARY KEY (`id`)
    -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE TABLE IF NOT EXISTS `line_items` (
    ->   `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
    ->   `item_id` int(11) unsigned DEFAULT NULL,
    ->   `quantity` int(11) unsigned DEFAULT 1,
    ->   PRIMARY KEY (`id`),
    ->   CONSTRAINT `fk` FOREIGN KEY (`item_id`) REFERENCES items (`id`)
    -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO `items` (`id`) VALUES (1);
Query OK, 1 row affected (0.00 sec)

mysql> CREATE TRIGGER `line_item_trigger` AFTER INSERT ON `line_items`
    -> FOR EACH ROW
    ->   UPDATE `items`
    ->   SET `quantity_sold` = `quantity_sold` + NEW.`quantity`,
    ->       `row_count_line_items` = (SELECT COUNT(`id`)
    ->                                 FROM `line_items`)
    ->   WHERE `id` = NEW.`item_id`;
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO `line_items` (`item_id`) VALUES (1);
Query OK, 1 row affected (0.08 sec)

mysql> SELECT `id`, `quantity_sold`, `row_count_line_items`
    -> FROM `items`;
+----+---------------+----------------------+
| id | quantity_sold | row_count_line_items |
+----+---------------+----------------------+
|  1 |             1 |                    1 |
+----+---------------+----------------------+
1 row in set (0.00 sec)

mysql> COMMIT;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT `id`, `item_id`, `quantity`
    -> FROM `line_items`;
+----+---------+----------+
| id | item_id | quantity |
+----+---------+----------+
|  1 |       1 |        1 |
+----+---------+----------+
1 row in set (0.00 sec)

请参阅db-fiddle