MySQL从5.0.2版本开始支持触发器。MySQL的触发器和存储过程一样,都是嵌入到MySQL服务器的一段程序。
触发器是由事件来触发某个操作,事件就是指用户的动作或者触发某项行为,这些事件包括INSERT、UPDATE、DELETE事件。如果定义了触发程序,当数据库执行这些语句时候,就相当于事件发生了,就会自动激发触发器执行相应的操作。
当对数据表中的数据执行插入、更新和删除操作,需要自动执行一些数据库逻辑时,可以使用触发器来实现。
创建触发器需要给出以下4条信息:

  • 唯一的触发器名(最好是在数据库范围内唯一);
  • 触发器关联的表;
  • 触发器应该响应的活动(DELETE、INSERT或UPDATE);
  • 触发器何时执行(处理之前或之后)。

只有表才支持触发器,视图和临时表不支持。触发器按每个表每个事件每次地定义,每个表每个事件每次只允许一个触发器。因此,每个表最多支持6个触发器(每条INSERT、UPDATE 和DELETE的之前和之后)。单一触发器不能与多个事件或多个表关联,所以如果需要一个对INSERT和UPDATE操作执行的触发器,则应该定义两个触发器。
如果BEFORE触发器失败,则MySQL将不执行请求的操作。如果BEFORE触发器或语句本身失败,MySQL将不执行AFTER触发器。

建立触发器

  1. CREATE TRIGGER 触发器名称
  2. {BEFORE|AFTER} {INSERT|UPDATE|DELETE} ON 表名
  3. FOR EACH ROW
  4. 触发器执行的语句块;
  • 表名:表示触发器监控的对象。
  • BEFORE|AFTER:表示触发的时间。BEFORE 表示在事件之前触发;AFTER 表示在事件之后触发。
  • INSERT|UPDATE|DELETE:表示触发的事件。
    • INSERT表示插入记录时触发;
    • UPDATE 表示更新记录时触发;
    • DELETE 表示删除记录时触发。
  • 触发器执行的语句块:可以是单条SQL语句,也可以是由BEGIN…END结构组成的复合语句块。

    INSERT触发器

    INSERT触发器在INSERT语句执行之前或之后执行

  • INSERT触发器代码内,可引用一个名为**NEW**的虚拟表,访问被插入的行;

  • BEFORE INSERT触发器中,**NEW**中的值也可以被更新(允许更改被插入的值);
  • 对于AUTO_INCREMENT列,**NEW**在INSERT执行之前包含0,在INSERT执行之后包含新的自动生成值。 ```sql CREATE TRIGGER neworder AFTER INSERT ON orders FOR EACH ROW SELECT NEW.order_num INTO @new_order_num;

INSERT INTO orders(order_date,cust_id) VALUES(Now(),10001);

SELECT @new_order_num;

  1. <a name="FgVfP"></a>
  2. ## DELETE触发器
  3. `DELETE`触发器在`DELETE`语句执行之前或之后执行
  4. - 在`DELETE`触发器代码内,可以引用一个名为`OLD`的虚拟表,访问被删除的行;
  5. - `OLD`中的值全都是只读的,不能更新。
  6. ```sql
  7. delimiter //
  8. CREATE TRIGGER deleter_order BEFORE DELETE ON orders
  9. FOR EACH ROW
  10. BEGIN
  11. INSERT INTO archive_orders(order_num,order_rate,cust_id)
  12. VALUES(OLD.order_num, OLD.order_date, OLD.cust_id);
  13. END //
  14. delimiter ;

UPDATE触发器

UPDATE触发器:UPDATE触发器在UPDATE语句执行之前或之后执行

  • UPDATE触发器代码中,可以引用一个名为OLD的虚拟表访问以前(UPDATE语句前)的值,引用一个名为NEW的虚拟表访问新 更新的值;
  • BEFORE UPDATE触发器中,NEW中的值可能也被更新(允许更改将要用于UPDATE语句中的值);
  • OLD中的值全都是只读的,不能更新。
    1. CREATE TRIGGER unpdate_vendor BEFORE UPDATE ON vendors
    2. FOR EACH ROW SET NEW.vend_state = UPPER(NEW.vend_state);

    示例

    ```sql — 创建数据表 CREATE TABLE test_trigger ( id INT PRIMARY KEY AUTO_INCREMENT, t_note VARCHAR(30) );

CREATE TABLE test_trigger_log ( id INT PRIMARY KEY AUTO_INCREMENT, t_log VARCHAR(30) ); — 创建触发器: 创建名称为before_insert的触发器,向test_trigger数据表插入数据之前, — 向test_trigger_log数据表中插入before_insert的日志信息。 DELIMITER //

CREATE TRIGGER before_insert BEFORE INSERT ON test_trigger FOR EACH ROW BEGIN INSERT INTO test_trigger_log (t_log) VALUES(‘before_insert’); END //

DELIMITER ;

— 向test_trigger数据表中插入数据 SELECT * FROM test_trigger_log;

— 创建名称为after_insert的触发器,向test_trigger数据表插入数据之后, — 向test_trigger_log数据表中插入after_insert的日志信息。 DELIMITER //

CREATE TRIGGER after_insert AFTER INSERT ON test_trigger FOR EACH ROW BEGIN INSERT INTO test_trigger_log (t_log) VALUES(‘after_insert’); END //

DELIMITER ;

— 向test_trigger数据表中插入数据 INSERT INTO test_trigger (t_note) VALUES (‘测试 AFTER INSERT 触发器’);

— 查看test_trigger_log数据表中的数据 SELECT * FROM test_trigger_log;

  1. <a name="lECep"></a>
  2. # 查看、删除触发器
  3. 查看触发器是查看数据库中已经存在的触发器的定义、状态和语法信息等。
  4. ```sql
  5. -- 查看当前数据库的所有触发器的定义
  6. SHOW TRIGGERS;
  7. -- 查看当前数据库中某个触发器的定义
  8. SHOW CREATE TRIGGER 触发器名;
  9. -- 从系统库information_schema的TRIGGERS表中查询触发器的信息。
  10. SELECT * FROM information_schema.TRIGGERS;

触发器不能更新或覆盖。为了修改一个触发器,必须先删除它, 然后再重新创建。

  1. -- 删除触发器
  2. DROP TRIGGER IF EXISTS 触发器名称;

触发器的优缺点

优点:

  • 触发器可以确保数据的完整性;
  • 触发器可以帮助记录操作日志,这有利于还原操作执行的具体场景,更好地定位问题。
  • 触发器还可以用在操作数据前,对数据进行合法性检查;

缺点:

  • 因为触发器存储在数据库中,并且由事件驱动,这就意味着触发器有可能不受应用层的控制。这对系统维护是非常有挑战的。
  • 相关数据变更,特别是数据表结构的变更,都可能会导致触发器出错进而影响数据操作的正常运行。这些都会由于触发器本身的隐蔽性,影响到应用中错误原因排查的效率。

注意
如果在子表中定义了外键约束,并且外键指定了ON UPDATE/DELETE CASCADE/SET NULL子句,此时修改父表被引用的键值或删除父表被引用的记录行时,也会引起子表的修改和删除操作,此时基于子表的UPDATE和DELETE语句定义的触发器并不会被激活。