目录

  • 一、触发器的概念
  • 为什么使用触发器
  • MySQL 中能够激活触发器的语句
  • 触发器操作的分类
  • 二、创建触发器
  • 创建有一条执行语句的操作
  • 创建包含多条执行语句的触发器
  • 三、查看触发器
  • 通过 SHOW TRIGGERS 语句查看触发器
  • 通过查看系统表 triggers 实现查看触发器
  • 四、删除触发器
  • 生词表


一、触发器的概念

触发器(TRIGGER)是 MySQL 的数据库对象之一,用来实现由一些表事件触发的某个操作。该对象与编程语言中的函数非常类似,都需要声明、执行等。但触发器的执行不是由程序调用,也不是由手工启动,而是由事件来触发、激活从而实现执行。

为什么使用触发器

在具体开发项目时,经常会遇到如下实例:

  • 在学生表中拥有字段:学生名字、学生总数,每当添加一条关于学生的记录,学生的总数就必须同时改变。
  • 在顾客信息表中拥有字段:顾客名称、电话、地址缩写,每当添加一条顾客的记录时,都需要检查电话号码格式是否正确,顾客地址缩写是否正确。

上述实例有个共同之处,即都需要在表发生改变时,自动进行一些处理。例如,对于第一个实例,可以创建一个触发器对象,每次添加一条学生记录时,就执行一次计算学生总数的操作。

MySQL 中能够激活触发器的语句

  • DELETE 语句
  • INSERT 语句
  • UPDATE 语句

触发器操作的分类

  • 创建触发器
  • 查看触发器
  • 删除触发器

二、创建触发器

按照激活触发器时所执行的语句数目,可以将触发器分为“一个执行语句的触发器” 和 “多个执行语句的触发器”。

创建有一条执行语句的操作

语法形式

CREATE TRIGGER trigger_name
	BEFORE|AFTER trigger_EVENT
		ON TABLE_NAME FOR EACH ROW trigger_STMT

元素

含义

trigger_name

所要创建的触发器的名字

BEFORE/AFTER

触发器执行的时机 (在事件之前/之后)

trigger_EVENT

触发器执行条件(包含DELETE、INSERT 和 UPDATE)

TABLE_NAME

触发器事件操作表的名字

FOR EACH ROW

表示任何一条记录上的操作满足触发事件都会触发该触发器

trigger_STMT

激活触发器后被执行的语句

【实例】
执行SQL 语句 CREATE TRIGGER,在数据库 company 中存在两个表对象:部门表(t_dept)和日记表(t_diary),创建触发器实现:向部门表中插入记录时,就会在插入之前向日记表中插入当前时间。
1、用前面的知识创建两个表格
建立部门表: t_dept

mysql> #建立表#
mysql> CREATE TABLE t_dept(
    -> deptno INT,
    -> dname VARCHAR(20),
    -> loc VARCHAR(40)
    -> );
Query OK, 0 rows affected (0.05 sec)
mysql> #查询表#
mysql> DESC t_dept;
+--------+-------------+------+-----+---------+-------+
| Field  | Type        | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| deptno | int         | YES  |     | NULL    |       |
| dname  | varchar(20) | YES  |     | NULL    |       |
| loc    | varchar(40) | YES  |     | NULL    |       |
+--------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

建立日记表 t_diary

mysql> #建立表#
mysql> CREATE TABLE t_diary(
    -> diaryno INT(11) PRIMARY KEY  AUTO_INCREMENT,
    -> tablename varchar(20),
    -> diarytime datetime
    -> );
Query OK, 0 rows affected, 1 warning (0.03 sec)

mysql> #查询表#
mysql> DESC t_diary;
+-----------+-------------+------+-----+---------+----------------+
| Field     | Type        | Null | Key | Default | Extra          |
+-----------+-------------+------+-----+---------+----------------+
| diaryno   | int         | NO   | PRI | NULL    | auto_increment |
| tablename | varchar(20) | YES  |     | NULL    |                |
| diarytime | datetime    | YES  |     | NULL    |                |
+-----------+-------------+------+-----+---------+----------------+
3 rows in set (0.01 sec)

2、创建触发器----一条执行语句
建立名为 tri_diarytime 的触发器用于在部门表 t_dept 插入任意一条记录时,就会在插入操作之前向表 t_diary 中插入当前的时间记录

mysql>  #创建触发器#
mysql> CREATE TRIGGER tri_diarytime
    ->     before insert
    ->            on t_dept for each row
    ->                   insert into t_diary values(null,'t_dept',now());

Query OK, 0 rows affected (0.02 sec)

3、验证
效验触发器 tri_dearytime 的功能
向表 t_dept 中插入一条记录,然后查看表 t_diary 中是否执行插入当前时间操作。

mysql> # 向表t_dept中插入一条记录 #
mysql> INSERT INTO t_dept VALUES(1,'cjgongdept','Shangxi');
Query OK, 1 row affected (8.24 sec)

mysql> #查看表 t_diary 中的记录 #
mysql> SELECT *
    -> FROM t_diary;
+---------+-----------+---------------------+
| diaryno | tablename | diarytime           |
+---------+-----------+---------------------+
|       1 | t_dept    | 2022-09-03 22:13:43 |
+---------+-----------+---------------------+
1 row in set (0.00 sec)

创建包含多条执行语句的触发器

语法形式

create trigger trigger_name
	BEFORE|AFTER trigger_event
		ON TABLE_NAME FOR EACH ROW
			BEGIN
			trigger_STMT
			END

在上述语句中,比 “ 只有一条执行语句的触发器”语法多出来两个关键字 “ BEGIN ” 和 “ END ” ,在这两个关键字之间是所要执行的多个执行语句的内容,他们之间用“;”隔开,这就与语句的结束符号“;”想冲突了。因此为了解决该问题,可以使用DELIMITER 语句,改变结束符。例如 “ DELIMITER$ ” ,可以用来实现将结束符号设置成“$$”

【实例】
1、创建触发器----包含多条执行语句
在数据库 company 中存在两个表对象:部门表 (t_dept) 和日记表(t_diary),创建触发器实现:当向部门表中插入记录时,就会在 插入之后 向日记表中插入两条记录。

mysql>  #创建触发器#
mysql> DELIMITER $
mysql> CREATE TRIGGER tri_diarytime2
    ->  AFTER INSERT
    ->          ON t_dept FOR EACH ROW
    ->                  BEGIN
    ->                          INSERT INTO t_diary VALUES(NULL,'t_dept',now());
                                INSERT INTO t_diary VALUES(NULL,'t_dept',now());
                        END
    ->                  $
Query OK, 0 rows affected (0.12 sec)
mysql> DELIMITER ;

在上述的语句中,首先通过“DELIMITER $ ” 语句设置结束符号为“$”,然后在关键字 BEGIN 和 END 之间编写了执行语句列表,最后通过 “DELIMETER ;” 语句将结束符号还原成默认的结束符号 “;”。
2、验证
验证之前,首先我们先查看一下当前数据库中有几个触发器(验证语句在后面介绍)

mysql>#查看触发器#
mysql> SHOW TRIGGERS \G
*************************** 1. row ***************************
             Trigger: tri_diarytime
               Event: INSERT
               Table: t_dept
           Statement: insert into t_diary values(null,'t_dept',now())
              Timing: BEFORE
             Created: 2022-08-20 14:42:41.94
            sql_mode: STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION
             Definer: root@localhost
character_set_client: gbk
collation_connection: gbk_chinese_ci
  Database Collation: utf8_general_ci
*************************** 2. row ***************************
             Trigger: tri_diarytime2
               Event: INSERT
               Table: t_dept
           Statement: BEGIN
                                INSERT INTO t_diary VALUES(NULL,'t_dept',now());
                                INSERT INTO t_diary VALUES(NULL,'t_dept',now());
                        END
              Timing: AFTER
             Created: 2023-02-18 16:34:12.05
            sql_mode: STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION
             Definer: root@localhost
character_set_client: gbk
collation_connection: gbk_chinese_ci
  Database Collation: utf8_general_ci
2 rows in set (0.00 sec)

从上面的结果中可以看到目前在本数据库中有两个触发器,一个是有一条语句的触发器,另一个是有两条语句的触发器。为了在验证的过程中不被第一个干扰,我们需要删除第一个触发器。

mysql>#删除触发器#
mysql> DROP TRIGGER tri_diarytime;
Query OK, 0 rows affected (0.02 sec)
mysql>#查看触发器#
mysql> SHOW TRIGGERS \G
*************************** 1. row ***************************
             Trigger: tri_diarytime2
               Event: INSERT
               Table: t_dept
           Statement: BEGIN
                                INSERT INTO t_diary VALUES(NULL,'t_dept',now());
                                INSERT INTO t_diary VALUES(NULL,'t_dept',now());
                        END
              Timing: AFTER
             Created: 2023-02-18 16:34:12.05
            sql_mode: STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION
             Definer: root@localhost
character_set_client: gbk
collation_connection: gbk_chinese_ci
  Database Collation: utf8_general_ci
1 row in set (0.01 sec)

这样,我们就可以向表 t_dept 中插入一条记录,然后查看表 t_diary 中是否执行插入2条当前时间操作。

mysql>#插入记录#
mysql> INSERT INTO t_dept VALUES(2,'cjgongdept','ShangXi');
Query OK, 1 row affected (0.00 sec)

mysql>#查看记录#
mysql> SELECT * FROM t_dept;
+--------+------------+---------+
| deptno | dname      | loc     |
+--------+------------+---------+
|      1 | cjgongdept | ShangXi |
|      2 | cjgongdept | ShangXi |
+--------+------------+---------+
2 rows in set (0.00 sec)

mysql>#查看记录#
mysql> SELECT * FROM t_diary;
+---------+-----------+---------------------+
| diaryno | tablename | diarytime           |
+---------+-----------+---------------------+
|       1 | t_dept    | 2022-09-03 22:13:43|
|       2 | t_dept    | 2023-02-18 16:47:47 |
|       3 | t_dept    | 2023-02-18 16:47:47 |
+---------+-----------+---------------------+
3 rows in set (0.00 sec)

通过插入指令,我们可以看到 t_dept 表中增加了一条记录,随后在 t_diary 表中同时增加了两个记录,这说明我们 tri_diarytime2 触发器创建成功。

三、查看触发器

在创建触发器时如果出现 “Trigger already exists”时,说明你所创建的触发器已经存在了,另外 MySQL 对于具有相同触发程序动作时机(Timing)和事件(Event)的触发器是不允许的。因此,在创建触发器前,应该查看本数据库中已经存在的触发器。

通过 SHOW TRIGGERS 语句查看触发器

语法形式

SHOW TRIGGERS \G

【实例】

mysql>#查看触发器#
mysql> SHOW TRIGGERS \G
*************************** 1. row ***************************
             Trigger: tri_diarytime2
               Event: INSERT
               Table: t_dept
           Statement: BEGIN
                                INSERT INTO t_diary VALUES(NULL,'t_dept',now());
                                INSERT INTO t_diary VALUES(NULL,'t_dept',now());
                        END
              Timing: AFTER
             Created: 2023-02-18 16:34:12.05
            sql_mode: STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION
             Definer: root@localhost
character_set_client: gbk
collation_connection: gbk_chinese_ci
  Database Collation: utf8_general_ci
1 row in set (0.00 sec)

单词

注释

Trigger

触发器的名称

Event

触发器的激活事件

Table

触发器对象触发事件所操作的表

Statement

触发器激活时所执行的语句

Timing

触发器被激活的时机

在上面的结果中我们能看到触发器的名称、激活事件、触发事件所操作的表、触发器激活时所执行的语句以及触发器被激活的时机。

通过查看系统表 triggers 实现查看触发器

在 MySQL 软件中,系统数据库 information_schema 中存在一个存储所有触发器信息的系统表 triggers,因此查询该表格的记录也可以实现查看触发器功能。

mysql>#选择数据库#
mysql> USE information_schema;
Database changed
mysql> SELECT * FROM triggers \G
*************************** 1. row ***************************
           TRIGGER_CATALOG: def
            TRIGGER_SCHEMA: sys
              TRIGGER_NAME: sys_config_insert_set_user
        EVENT_MANIPULATION: INSERT
      EVENT_OBJECT_CATALOG: def
       EVENT_OBJECT_SCHEMA: sys
        EVENT_OBJECT_TABLE: sys_config
              ACTION_ORDER: 1
          ACTION_CONDITION: NULL
          ACTION_STATEMENT: BEGIN
    IF @sys.ignore_sys_config_triggers != true AND NEW.set_by IS NULL THEN
        SET NEW.set_by = USER();
    END IF;
END
        ACTION_ORIENTATION: ROW
             ACTION_TIMING: BEFORE
ACTION_REFERENCE_OLD_TABLE: NULL
ACTION_REFERENCE_NEW_TABLE: NULL
  ACTION_REFERENCE_OLD_ROW: OLD
  ACTION_REFERENCE_NEW_ROW: NEW
                   CREATED: 2022-03-15 21:30:46.94
                  SQL_MODE: ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DA
TE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
                   DEFINER: mysql.sys@localhost
      CHARACTER_SET_CLIENT: utf8mb4
      COLLATION_CONNECTION: utf8mb4_0900_ai_ci
        DATABASE_COLLATION: utf8mb4_0900_ai_ci
*************************** 2. row ***************************
           TRIGGER_CATALOG: def
            TRIGGER_SCHEMA: sys
              TRIGGER_NAME: sys_config_update_set_user
        EVENT_MANIPULATION: UPDATE
      EVENT_OBJECT_CATALOG: def
       EVENT_OBJECT_SCHEMA: sys
        EVENT_OBJECT_TABLE: sys_config
              ACTION_ORDER: 1
          ACTION_CONDITION: NULL
          ACTION_STATEMENT: BEGIN
    IF @sys.ignore_sys_config_triggers != true AND NEW.set_by IS NULL THEN
        SET NEW.set_by = USER();
    END IF;
END
        ACTION_ORIENTATION: ROW
             ACTION_TIMING: BEFORE
ACTION_REFERENCE_OLD_TABLE: NULL
ACTION_REFERENCE_NEW_TABLE: NULL
  ACTION_REFERENCE_OLD_ROW: OLD
  ACTION_REFERENCE_NEW_ROW: NEW
                   CREATED: 2022-03-15 21:30:46.94
                  SQL_MODE: ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DA
TE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
                   DEFINER: mysql.sys@localhost
      CHARACTER_SET_CLIENT: utf8mb4
      COLLATION_CONNECTION: utf8mb4_0900_ai_ci
        DATABASE_COLLATION: utf8mb4_0900_ai_ci
*************************** 3. row ***************************
           TRIGGER_CATALOG: def
            TRIGGER_SCHEMA: company
              TRIGGER_NAME: tri_diarytime2
        EVENT_MANIPULATION: INSERT
      EVENT_OBJECT_CATALOG: def
       EVENT_OBJECT_SCHEMA: company
        EVENT_OBJECT_TABLE: t_dept
              ACTION_ORDER: 1
          ACTION_CONDITION: NULL
          ACTION_STATEMENT: BEGIN
                                INSERT INTO t_diary VALUES(NULL,'t_dept',now());
                                INSERT INTO t_diary VALUES(NULL,'t_dept',now());
                        END
        ACTION_ORIENTATION: ROW
             ACTION_TIMING: AFTER
ACTION_REFERENCE_OLD_TABLE: NULL
ACTION_REFERENCE_NEW_TABLE: NULL
  ACTION_REFERENCE_OLD_ROW: OLD
  ACTION_REFERENCE_NEW_ROW: NEW
                   CREATED: 2023-02-18 16:34:12.05
                  SQL_MODE: STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION
                   DEFINER: root@localhost
      CHARACTER_SET_CLIENT: gbk
      COLLATION_CONNECTION: gbk_chinese_ci
        DATABASE_COLLATION: utf8_general_ci
3 rows in set (0.00 sec)

从上面的查询结果可以看出来,在 MySQL 中存在3个触发器,前两个为系统自带的,最后一个是我们建立的有两个执行语句的触发器。

四、删除触发器

语法

DROP TRIGGER trigger_name

trigger_name------所要删除的触发器名称


生词表

单词

读音

译文

MySQL

Trigger

英 [ˈtrɪɡə]

vt.触发;引起;发动;开动;起动 n.触发器;(枪的)扳机;(尤指引发不良反应或发展的)起因,诱因;引爆器

触发器

Event

英 [ɪˈvent]

n.事件;发生的事情;

事件

ROW

英[rəʊ , raʊ]

n.一行; 一排; 一列;

记录

DELIMITER

英 [diːˈlɪmɪtə]

n.定界符

设置结束符

Drop

英[drɒp]

n. 滴; 下降; 下跌; v. (意外地)落下,掉下,使落下;

删除