09-MySQL触发器
1 触发器简介(trigger)
- 触发器和存储过程一样,都是嵌入到MySQL的一段程序。
- 触发器是由时间来出发某个操作,这些事件包括INSERT、UPDATE和DELETE语句。
- 定义触发器后,当数据库执行到这些语句的时候就会激发触发器执行相应的操作,触发程序是与表有关的命名数据库对象。
2 创建触发器
触发器是一个特殊的存储过程,存储过程需要CALL语句进行调用,触发器的执行不需要使用CALL语句的调用。
触发器可以查询其他表,而且可以包含复杂的SQL语句。它们主要用于满足复杂的业务规则或要求。例如:可以根据客户当前的账户状态,控制是否允许插入新订单。
3 创建触发器
3.1 创建一个单执行语句的触发器
语法:
create trigger trigger_name trigger_time trigger_event
on tbl_name for each row trigger_stmt
trigger_name是触发器名称,用户自行制定;trigger_time表示触发时机,可以指定before或者after;trigger_event 表示触发事件,包括insert ,update ,delete; tbl_name标识建立触发器的表名,即在那张表上建立触发器;trigger+stmt是触发器执行语句。
例子:创建一个单执行语句的触发器,代码如下:
-- 创建account表,表中有两个字段
create table account (acct_num int, amount decimal(10,2));
创建一个名为ins_sum的触发器,触发的条件是向数据表account插入数据之前,对新插入的数account字段值进行求和计算。
-- 创建一个名为ins_sum的触发器
create trigger ins_sum before insert on account
for each row set @sum = @sum + NEW.amount;
mysql> set @sum = 0;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into account values(1,1.00);
Query OK, 1 row affected (0.01 sec)
mysql> select @sum;
+------+
| @sum |
+------+
| 1.00 |
+------+
1 row in set (0.00 sec)
-- 插入账户数据
mysql> insert into account values(2,2.00);
Query OK, 1 row affected (0.01 sec)
-- 查询sum变量的值
mysql> select @sum;
+------+
| @sum |
+------+
| 3.00 |
+------+
1 row in set (0.00 sec)
3.2 创建有多个执行语句的触发器
语法:
create trigger trigger_name trigger_time trigger_event
on tb1_name for each row
begin
语句执行列表
end
trigger_name是触发器名称,用户自行制定;trigger_time表示触发时机,可以指定before或者after;trigger_event 表示触发事件,包括insert ,update ,delete; tbl_name标识建立触发器的表名,即在那张表上建立触发器;触发器程序可以使用begin和end作为开始和结束,中间包含多条语句。
例子:创建一个包含多个执行语句的触发器,代码如下:
创建测试表:
mysql> create table test1(a1 int);
Query OK, 0 rows affected (0.03 sec)
mysql> create table test2(a2 int);
Query OK, 0 rows affected (0.02 sec)
mysql> create table test3(a3 int not null auto_increment primary key);
Query OK, 0 rows affected (0.02 sec)
mysql> create table test4(
-> a4 int not null auto_increment primary key,
-> b4 int default 0
-> );
Query OK, 0 rows affected (0.01 sec)
创建触发器:
mysql> delimiter //
mysql> create trigger testrf before insert on test1
-> for each row begin
-> insert into test2 set a2 = new.a1; -- 像test2插入test1的值
-> delete from test3 where a3 = new.a1; -- 删除test3中相同的序列
-> update test4 set b4=b4+1 where a4 = new.a1; -- 更新test4中的b4,即插入的值相同的个数
-> end
-> //
Query OK, 0 rows affected (0.01 sec)
mysql> delimiter ;
mysql> insert into test3 (a3) values (null), (null), (null), (null), (null), (nu
ll), (null), (null), (null), (null);
Query OK, 10 rows affected (0.00 sec)
Records: 10 Duplicates: 0 Warnings: 0
mysql> insert into test4 (a4) values (0), (0), (0), (0), (0), (0), (0), (0), (0);
mysql> select * from test4;
+----+------+
| a4 | b4 |
+----+------+
| 1 | 0 |
| 2 | 0 |
| 3 | 0 |
| 4 | 0 |
| 5 | 0 |
| 6 | 0 |
| 7 | 0 |
| 8 | 0 |
| 9 | 0 |
+----+------+
9 rows in set (0.00 sec)
mysql> select * from test3;
+----+
| a3 |
+----+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
| 10 |
+----+
10 rows in set (0.00 sec)
mysql> select * from test2;
Empty set (0.00 sec)
mysql> select * from test1;
Empty set (0.00 sec)
mysql> insert into test1 values (1),(3),(1),(7),(1),(8),(4),(4);
Query OK, 8 rows affected (0.01 sec)
Records: 8 Duplicates: 0 Warnings: 0
mysql> select * from test1;
+------+
| a1 |
+------+
| 1 |
| 3 |
| 1 |
| 7 |
| 1 |
| 8 |
| 4 |
| 4 |
+------+
8 rows in set (0.00 sec)
-- 向test2插入test1的值
mysql> select * from test2;
+------+
| a2 |
+------+
| 1 |
| 3 |
| 1 |
| 7 |
| 1 |
| 8 |
| 4 |
| 4 |
+------+
8 rows in set (0.00 sec)
-- 删除test3中相同的序列
mysql> select * from test3;
+----+
| a3 |
+----+
| 2 |
| 5 |
| 6 |
| 9 |
| 10 |
+----+
5 rows in set (0.00 sec)
-- 更新test4中的b4,即插入的值相同的个数
mysql> select * from test4;
+----+------+
| a4 | b4 |
+----+------+
| 1 | 3 |
| 2 | 0 |
| 3 | 1 |
| 4 | 2 |
| 5 | 0 |
| 6 | 0 |
| 7 | 1 |
| 8 | 1 |
| 9 | 0 |
+----+------+
9 rows in set (0.00 sec)
4 查看触发器
mysql> show triggers \G;
*************************** 1. row ***************************
Trigger: ins_sum
Event: INSERT
Table: account
Statement: set @sum= @sum+new.account
Timing: BEFORE
Created: 2018-05-01 18:16:44.22
sql_mode: STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITU
TION
Definer: root@localhost
character_set_client: utf8
collation_connection: utf8_general_ci
Database Collation: utf8_general_ci
*************************** 2. row ***************************
Trigger: testrf
Event: INSERT
Table: test1
Statement: begin
insert into test2 set a2 = new.a1;
delete from test3 where a3 = new.a1;
update test4 set b4=b4+1 where a4 = new.a1;
end
Timing: BEFORE
Created: 2018-05-01 18:30:50.90
sql_mode: STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITU
TION
Definer: root@localhost
character_set_client: utf8
collation_connection: utf8_general_ci
Database Collation: utf8_general_ci
2 rows in set (0.00 sec)
参数 | 备注 |
---|---|
Trigger | 触发器名称 |
Event | 激活触发器的时间 |
Table | 触发器作用的表 |
Statement | 触发器执行的操作 |
Timing | 触发器执行的时间 |
4.1 查看triggers 表中查看触发器信息
-- 语法
select * from information_schema.triggers where condition;
mysql> select * from information_schema.triggers where trigger_name= 'ins_sum' \
G;
*************************** 1. row ***************************
TRIGGER_CATALOG: def
TRIGGER_SCHEMA: test
TRIGGER_NAME: ins_sum
EVENT_MANIPULATION: INSERT
EVENT_OBJECT_CATALOG: def
EVENT_OBJECT_SCHEMA: test
EVENT_OBJECT_TABLE: account
ACTION_ORDER: 1
ACTION_CONDITION: NULL
ACTION_STATEMENT: set @sum= @sum+new.account
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: 2018-05-01 18:16:44.22
SQL_MODE: STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SU
BSTITUTION
DEFINER: root@localhost
CHARACTER_SET_CLIENT: utf8
COLLATION_CONNECTION: utf8_general_ci
DATABASE_COLLATION: utf8_general_ci
1 row in set (0.06 sec)
ERROR:
No query specified
5 触发器的使用
触发程序是与表有关的命名数据库对象,当表上出现特定事件时,将激活该对象,在某些触发程序的用法中,可用于检查插入到表中的值,或最更新涉及的值进行计算。
触发程序与表相关,当对表执行insert、delete 、update语句时,将激活触发程序,可以将触发程序设置为在执行特定之前或者之后。
例子:创建一个account表插入记录后,更新myevent数据表的触发器,代码如下:
mysql> create trigger trig_insert after insert on account
-> for each row insert into myevent values(2,'after insert');
Query OK, 0 rows affected (0.01 sec)
mysql> create trigger trig_insert after insert on account
-> for each row insert into myevent values(2,'after insert');
Query OK, 0 rows affected (0.01 sec)
mysql> insert into account values (1,1.00),(2,2.00);
ERROR 1146 (42S02): Table 'test.myevent' doesn't exist
mysql> create table myevent (
-> id int ,
-> name varchar(20)
-> );
Query OK, 0 rows affected (0.03 sec)
mysql> insert into account values (1,1.00),(2,2.00);
Query OK, 2 rows affected (0.01 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> select * from myevent;
+------+--------------+
| id | name |
+------+--------------+
| 2 | after insert |
| 2 | after insert |
+------+--------------+
2 rows in set (0.00 sec)
5 删除触发器
语法:
drop trigger [schema_name] trigger_name
schema_name为数据库名,可选,trigger_name 是要删除的触发器的名称。
drop trigger test.ins;
6 Q&A
6.1 使用触发器是注意
如果已经对一个表创建了before insert ,那么再创建before insert时就会报错
6.2 及时删除不需要的触发器
触发器定义后,每次执行触发操作,都会激活触发器并执行触发器中的语句。如果需求发生变化,而触发器没有进行相应的改变或者删除,则触发器依然会执行旧的语句,从而影响新的数据的完整性。因此要将不再使用的触发器及时删除。