定义
触发器的对象是表,当表上出现特定的事件(增、删、改)时触发该程序的执行。
触发器的类型
- UPDATE
- update 操作
DELETE
- delete 操作
- replace 操作
:::warning 注意:drop,truncate 等 DDL 操作不会触发 DELETE。 :::
INSERT
- insert 操作
- load data 操作
- replace 操作
:::warning
注意:replace 操作可能会触发两次,一次是 DELETE 类型的触发器,一次是 INSERT 类型的触发器。
:::
:::warning
- MySQL 5.6 版本针对一张表,同一个类型的触发器只能有一个。
- MySQL 5.7 版本针对一张表,允许多个同一类型的触发器。
- 触发器只触发 DML 操作,不会触发 DDL 操作(create、drop 等操作)。 :::
创建触发器
语法
CREATE
[DEFINER = user]
TRIGGER trigger_name -- 触发器名字
trigger_time trigger_event -- 触发时间和事件
ON tbl_name FOR EACH ROW
[trigger_order]
trigger_body
trigger_time: { BEFORE | AFTER } -- 事件之前还是之后触发
trigger_event: { INSERT | UPDATE | DELETE } -- 三个类型事件
trigger_order: { FOLLOWS | PRECEDES } other_trigger_name
- trigger_name:触发器名称
- tirgger_time:触发执行时间
- BEFORE:事件之前触发
- AFTER:事件之后触发
- trigger_event:触发事件
- INSERT:插入某一行时激活触发器,INSERT,LOAD DATA,REPLACE 语句可以触发
- UPDATE:更改某一行时激活触发器,UPDATE 语句可以触发
- DELETE:删除某一行时激活触发器,DELETE,REPLACE 语句可以触发
- tbl_name:触发器要执行的哪张表
- FOR EACH ROW:触发频率为每一行触发一次
- trigger_body:触发器的程序体,可以是一条SQL语句或者是用 BEGIN 和 END 包含的多条语句
创建只有一个执行语句的触发器
CREATE TRIGGER 触发器名 BEFORE|AFTER 触发事件 ON 表名 FOR EACH ROW 执行语句;
创建有多个执行语句的触发器
CREATE TRIGGER 触发器名 BEFORE|AFTER 触发事件
ON 表名 FOR EACH ROW
BEGIN
执行语句列表
END;
MySQL 默认是以分号(;)作为结束执行符号,与触发器执行语句列表中需要的分行起冲突,为解决此问题可用DELIMITER,如DELIMITER ;; ,就是将结束符号变成 ;;。
DELIMITER ;;
CREATE TRIGGER 触发器名 BEFORE|AFTER 触发事件
ON 表名 FOR EACH ROW
BEGIN
执行语句列表
END ;;
DELIMITER;
删除触发器
DROP TRIGGER IF EXISTS tb_name;
示例
数据准备:
-- 创建user表
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`account` varchar(255) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
`address` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- 创建对user表操作历史表
DROP TABLE IF EXISTS `user_history`;
CREATE TABLE `user_history` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`user_id` bigint(20) NOT NULL,
`operatetype` varchar(200) NOT NULL,
`operatetime` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
创建 user 表插入事件对应的触发器
DROP TRIGGER IF EXISTS `tri_insert_user`;
DELIMITER ;;
CREATE TRIGGER `tri_insert_user` AFTER INSERT ON `user` FOR EACH ROW begin
INSERT INTO user_history(user_id, operatetype, operatetime) VALUES (new.id, 'add a user', now());
end
;;
DELIMITER ;
- old.col:更新以前的列值(只读)。
- new.col:更新以后的列值。
创建 user 表更新事件对应的触发器
DROP TRIGGER IF EXISTS `tri_update_user`;
DELIMITER ;;
CREATE TRIGGER `tri_update_user` AFTER UPDATE ON `user` FOR EACH ROW begin
INSERT INTO user_history(user_id,operatetype, operatetime) VALUES (new.id, 'update a user', now());
end
;;
DELIMITER ;
创建 user 表删除事件对应的触发器
DROP TRIGGER IF EXISTS `tri_delete_user`;
DELIMITER ;;
CREATE TRIGGER `tri_delete_user` AFTER DELETE ON `user` FOR EACH ROW begin
INSERT INTO user_history(user_id, operatetype, operatetime) VALUES (old.id, 'delete a user', now());
end
;;
DELIMITER ;
至此,全部表及触发器创建完成,开始验证结果,分别做插入、修改、删除事件,执行以下语句,观察 user_history是否自动产生操作记录。
INSERT INTO user(account, name, address) VALUES ('user1', 'user1', 'user1');
INSERT INTO user(account, name, address) VALUES ('user2', 'user2', 'user2');
UPDATE user SET name = 'user3', account = 'user3', address='user3' where name='user1';
DELETE FROM `user` where name = 'user2';
触发器总结
- 触发器对性能有损耗,应当非常慎重使用。
- 对于事务表,触发器执行失败则整个语句回滚。
- Row 格式主从复制,触发器不会在从库上执行。
- 因为从库复制的肯定是主库已经提交的数据,既然已经提交了说明触发器已经被触发过了,所以从库不会执行。
- 使用触发器时应防止递归执行。
delimiter //
create trigger trg_test
before update on 'test_trigger'
for each row
begin
update test_trigger set score=20 where name = old.name; -- 又触发了update操作,循环触发了
end;//
作者:殷建卫 链接:https://www.yuque.com/yinjianwei/vyrvkf/iq4wqs 来源:殷建卫 - 架构笔记 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。