> For the complete documentation index, see [llms.txt](https://hezhiqiang-book.gitbook.io/mysql/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://hezhiqiang-book.gitbook.io/mysql/di-si-zhang/chuang-jian-duo-ge-chu-fa-qi.md).

# 创建多个触发器

在本教程中，您将学习如何为MySQL中相同的事件和动作时间创建多个触发器。

本教程与*MySQL5.7.2+*&#x7248;本相关。 如果您有一个较旧版本的MySQL，本教程中的语句将无法正常工作。

在*MySQL5.7.2+*&#x7248;本之前，您只能为表中的事件创建一个触发器，例如，只能为`BEFORE UPDATE`或`AFTER UPDATE`事件创建一个触发器。 *MySQL 5.7.2+*&#x7248;本解决了这样限制，并允许您为表中的相同事件和动作时间创建多个触发器。当事件发生时，触发器将依次激活。

参考[创建第一个触发器](http://www.yiibai.com/create-the-first-trigger-in-mysql.html)中的语法。如果表中有相同事件有多个触发器，MySQL将按照创建的顺序调用触发器。要更改触发器的顺序，需要在`FOR EACH ROW`子句之后指定`FOLLOWS`或`PRECEDES`。如下说明 -

* `FOLLOWS`选项允许新触发器在现有触发器之后激活。
* `PRECEDES`选项允许新触发器在现有触发器之前激活。

以下是使用显式顺序创建新的附加触发器的语法：

```sql
DELIMITER $$
CREATE TRIGGER  trigger_name
[BEFORE|AFTER] [INSERT|UPDATE|DELETE] ON table_name
FOR EACH ROW [FOLLOWS|PRECEDES] existing_trigger_name
BEGIN
…
END$$
DELIMITER ;
```

## MySQL多重触发器示例

我们来看如何一个在表中的同一个事件和动作上，创建多个触发器的例子。

下面将使用[示例数据库(yiibaidb)](http://www.yiibai.com/mysql/sample-database.html)中的`products`表进行演示。假设，每当更改产品的价格(`MSRP`列)时，要将旧的价格记录在一个名为`price_logs`的表中。

首先，使用[CREATE TABLE](http://www.yiibai.com/mysql/create-table.html)语句创建一个新的`price_logs`表，如下所示：

```sql
USE yiibaidb;
CREATE TABLE price_logs (
  id INT(11) NOT NULL AUTO_INCREMENT,
  product_code VARCHAR(15) NOT NULL,
  price DOUBLE NOT NULL,
  updated_at TIMESTAMP NOT NULL DEFAULT 
             CURRENT_TIMESTAMP 
             ON UPDATE CURRENT_TIMESTAMP,

  PRIMARY KEY (id),

  KEY product_code (product_code),

  CONSTRAINT price_logs_ibfk_1 FOREIGN KEY (product_code) 
  REFERENCES products (productCode) 
  ON DELETE CASCADE 
  ON UPDATE CASCADE
);
```

*其次*，当表的`BEFORE UPDATE`事件发生时，创建一个新的触发器。触发器名称为`before_products_update`，具体实现如下所示：

```sql
DELIMITER $$

CREATE TRIGGER before_products_update 
   BEFORE UPDATE ON products 
   FOR EACH ROW 
BEGIN
     INSERT INTO price_logs(product_code,price)
     VALUES(old.productCode,old.msrp);
END$$

DELIMITER ;
```

*第三*，我们更改产品的价格，并使用以下[UPDATE](http://www.yiibai.com/mysql/update-data.html)语句，最后查询`price_logs`表：

```sql
UPDATE products
SET msrp = 95.1
WHERE productCode = 'S10_1678';
-- 查询结果价格记录
SELECT * FROM price_logs;
```

上面查询语句执行后，得到以下结果 -

```sql
+----+--------------+-------+---------------------+
| id | product_code | price | updated_at          |
+----+--------------+-------+---------------------+
|  1 | S10_1678     |  95.7 | 2017-08-03 02:46:42 |
+----+--------------+-------+---------------------+
1 row in set
```

可以看到结果中，它按我们预期那样工作了。

假设不仅要看到旧的价格，改变的时候，还要记录是谁修改了它。 我们可以向`price_logs`表添加其他列。 但是，为了实现多个触发器的演示，我们将创建一个新表来存储进行更改的用户的数据。这个新表的名称为`user_change_logs`，结构如下：

```sql
USE yiibaidb;
CREATE TABLE user_change_logs (
  id int(11) NOT NULL AUTO_INCREMENT,
  product_code varchar(15) DEFAULT NULL,
  updated_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP 
  ON UPDATE CURRENT_TIMESTAMP,

  updated_by varchar(30) NOT NULL,

  PRIMARY KEY (id),

  KEY product_code (product_code),

  CONSTRAINT user_change_logs_ibfk_1 FOREIGN KEY (product_code) 
  REFERENCES products (productCode) 
  ON DELETE CASCADE ON UPDATE CASCADE
);
```

现在，我们创建一个在`products`表上的`BEFORE UPDATE`事件上激活的第二个触发器。 此触发器将更改的用户信息更新到`user_change_logs`表。 它在`before_products_update`触发后被激活。

```sql
DELIMITER $$
CREATE TRIGGER before_products_update_2 
   BEFORE UPDATE ON products 
   FOR EACH ROW FOLLOWS before_products_update
BEGIN
   INSERT INTO user_change_logs(product_code,updated_by)
   VALUES(old.productCode,user());
END$$

DELIMITER ;
```

下面我们来做一个快速测试。

*首先*，使用[UPDATE语句](http://www.yiibai.com/mysql/update-data.html)更新指定产品的价格，如下：

```sql
UPDATE products
SET msrp = 95.3
WHERE productCode = 'S10_1678';
```

*其次*，分别从`price_logs`和`user_change_logs`表查询数据：

```sql
SELECT * FROM price_logs;
```

上面查询语句执行后，得到以下结果 -

```sql
mysql> SELECT * FROM price_logs;
+----+--------------+-------+---------------------+
| id | product_code | price | updated_at          |
+----+--------------+-------+---------------------+
|  1 | S10_1678     |  95.7 | 2017-08-03 02:46:42 |
|  2 | S10_1678     |  95.1 | 2017-08-03 02:47:21 |
+----+--------------+-------+---------------------+
2 rows in set
```

```sql
SELECT * FROM user_change_logs;
```

上面查询语句执行后，得到以下结果 -

```sql
mysql> SELECT * FROM user_change_logs;
+----+--------------+---------------------+----------------+
| id | product_code | updated_at          | updated_by     |
+----+--------------+---------------------+----------------+
|  1 | S10_1678     | 2017-08-03 02:47:21 | root@localhost |
+----+--------------+---------------------+----------------+
1 row in set
```

如上所见，两个触发器按照预期的顺序激活执行相关操作了。

## 触发器顺序

如果使用`SHOW TRIGGERS`语句，则不会在表中看到触发激活同一事件和操作的顺序。

```sql
SHOW TRIGGERS FROM yiibaidb;
```

要查找此信息，需要如下查询`information_schema`数据库的`triggers`表中的`action_order`列，如下查询语句 -

```sql
SELECT 
    trigger_name, action_order
FROM
    information_schema.triggers
WHERE
    trigger_schema = 'yiibaidb'
ORDER BY event_object_table , 
         action_timing , 
         event_manipulation;
```

上面查询语句执行后，得到以下结果 -

```sql
mysql> SELECT 
    trigger_name, action_order
FROM
    information_schema.triggers
WHERE
    trigger_schema = 'yiibaidb'
ORDER BY event_object_table , 
         action_timing , 
         event_manipulation;
+--------------------------+--------------+
| trigger_name             | action_order |
+--------------------------+--------------+
| before_employee_update   |            1 |
| before_products_update   |            1 |
| before_products_update_2 |            2 |
+--------------------------+--------------+
3 rows in set
```

在本教程中，我们向您展示了如何在MySQL的表中为同一事件创建多个触发器。
