触发器介绍
MySQL 的触发器和存储过程一样,都是嵌入到 MySQL 中的一段程序,是 MySQL中管理数据的有力工具。通过对数据表的相关操作来触发、激活从而实现执行。比如当对 student 表进行操作( INSERT, DELETE 或 UPDATE)时就会激活它执行。
作用:
触发器与数据表关系密切,主要用于保护表中的数据。特别是当有多个表具有一定的相互联系的时候,触发器能够让不同的表保持数据的一致性、日志记录 , 数据校验等操作
优点:
触发器的执行是自动的,当对触发器相关表的数据做出相应的修改后立即执行。
触发器可以实施比 FOREIGN KEY 约束、CHECK 约束更为复杂的检查和操作。
触发器可以实现表数据的级联更改,在一定程度上保证了数据的完整性。
缺点:
使用触发器实现的业务逻辑在出现问题时很难进行定位,特别是涉及到多个触发器的情况下,会使后期维护变得困难。
大量使用触发器容易导致代码结构被打乱,增加了程序的复杂性,
如果需要变动的数据量较大时,触发器的执行效率会非常低。
触发器分类
mysql中 触发器分为三类
INSERT 触发器、 UPDATE 触发器和 DELETE 触发器
使用别名OLD和NEW来引用触发器中发生变化的记录内容,这与其他的数据库是相似的。现在触发器还只支持行级触发不支持语句级触发
INSERT触发器
语法格式
CREATE <触发器名> < BEFORE | AFTER >
<INSERT | UPDATE | DELETE >
ON <表名> FOR EACH Row<触发器主体>
-- 创建触发器语法
delimiter $$ -- delimiter表示触发器 $$表示将这段SQL的结束符改为$$
create trigger 触发器名称
after 或 before -- 操作之前或之后触发
on 表名 -- 由哪张表操作触发
for each row -- 针对每一行数据
begin -- 触发器主体
-- 要执行的insert语句 NEW.userId表示使用userId作为新插入行的userId外键
insert into t_log values(null,NEW.userId,'操作记录',xxx,...)
end -- 触发器主体结束
$$ -- 触发器结束
delimiter ; -- 将结束符改回分号
创建表
CREATE TABLE `t_user` (
`usrId` int NOT NULL AUTO_INCREMENT,
`uName` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL,
`uEmail` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL,
`uAge` int DEFAULT NULL,
PRIMARY KEY (`usrId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
CREATE TABLE `t_points` (
`pId` int NOT NULL AUTO_INCREMENT,
`points` double DEFAULT NULL COMMENT '积分',
`createTime` datetime DEFAULT NULL,
`uId` int DEFAULT NULL,
PRIMARY KEY (`pId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
创建INSERT触发器
在新增用户时 触发添加用户积分信息
-- 创建触发器
DELIMITER $$ -- 更改默认的语句分隔符$$ 这样就可以在触发器内部使用分号作为语句分隔符
CREATE TRIGGER after_user_insert_points -- 触发器名称 新增用户之后添加用户的积分信息
AFTER INSERT ON t_user -- 在t_user表新增数据之后触发
FOR EACH ROW -- 针对t_user中每一行数据
BEGIN -- 触发器开始 触发器的主体
-- 要触发的操作 即 向积分表添加一条记录 注意:添加到值要与字段匹配
INSERT INTO t_points(points,createTime,uId) VALUES(0.00,NOW(),NEW.usrId);
END -- 触发器主体结束
$$ -- 触发器定义结束
DELIMITER ; -- 将语句分隔符改回到分号
-- 测试
INSERT INTO t_user VALUES(NULL,'Tom','tom@usa.com',18);
DELETE触发器
思考:删除数据时 应先删除从表中数据还是主表中数据
应先删除从表中数据 在删除主表中数据 否则从表中的外键就无法关联到主表
触发 当用户注销时 将用户积分信息删除并同时删除主表中对应的用户信息
表还是使用上边新增触发器时创建的两张表
创建DELETE触发器
-- 当用户注销时 删除用户记录 同时清空用户其他信息 如积分记录
-- 正常业务操作时 应先删除用户积分记录 最后才会删除用户信息
DELIMITER $$ -- 更改默认的语句分隔符$$ 这样就可以在触发器内部使用分号作为语句分隔符
CREATE TRIGGER user_delete_points -- 触发器名称 新增用户之后添加用户的积分信息
BEFORE DELETE ON t_user -- 在t_user表中数据删除之前触发
FOR EACH ROW -- 针对t_user中每一行数据
BEGIN -- 触发器开始 触发器的主体
-- old与new类似 old表示之前存在的
DELETE FROM t_points WHERE uId=old.usrId;
END -- 触发器主体结束
$$ -- 触发器定义结束
DELIMITER ; -- 将语句分隔符改回到分号
-- 测试删除操作
DELETE FROM t_user WHERE usrId=1;
UPDATE触发器1
更新数据时触发的操作
修改用户信息时 同时向日志表添加一条记录
用户表使用前面创建的,需要新增一张日志表
创建t_logs表
CREATE TABLE `t_logs` (
`id` int NOT NULL AUTO_INCREMENT,
`remark` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '操作描述',
`uId` int DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
创建UPDATE触发器
-- 当更新用户信息时 向操作记录中添加一条日志信息
DELIMITER $$ -- 更改默认的语句分隔符$$ 这样就可以在触发器内部使用分号作为语句分隔符
CREATE TRIGGER user_update_trigger2 -- 触发器名称 修改用户之后添加操作记录信息
AFTER UPDATE ON t_user -- 在t_user表中数据修改之后触发
FOR EACH ROW -- 针对t_user中每一行数据
BEGIN -- 触发器开始 触发器的主体
-- old与new类似 old表示之前存在的
INSERT INTO t_logs VALUES(NULL,'用户更新了数据',old.usrId);
END -- 触发器主体结束
$$ -- 触发器定义结束
DELIMITER ; -- 将语句分隔符改回到分号
-- 测试
UPDATE t_user SET uEmail='Jerry@etjava.com'WHERE usrId=2;
UPDATE触发器2
用户的年龄不允许超过35
如果超过了给出错误提示
创建UPDATE触发器
DELIMITER &&
CREATE TRIGGER update_user_tip
BEFORE UPDATE ON t_user
FOR EACH ROW
BEGIN
IF new.uAge>35 THEN
SIGNAL SQLSTATE '42002' -- SIGNAL使用大写
SET MESSAGE_TEXT = '用户年龄不能大于35岁', -- MESSAGE_TEXT 大写
MYSQL_ERRNO = 42002; -- MYSQL_ERRNO 大写
END IF;
END
&&
DELIMITER ;

多条件触发器
DELIMITER $$
CREATE TRIGGER aaa
AFTER UPDATE ON t_a -- a表更新之后触发
FOR EACH ROW
BEGIN
IF NEW.`status`=3 THEN
UPDATE t_b SET `status`=NEW.`status` WHERE aId=NEW.`aId`;
END IF;
IF NEW.`status`=4 THEN
UPDATE t_b SET `status`=NEW.`status` WHERE aId=NEW.`aId`;
END IF;
END
$$
DELIMITER ;