触发器(Trigger)是与表相关联的特殊存储过程 ,它不能手动调用 ,而是在执行 INSERT/UPDATE/DELETE 操作时自动触发。常用于数据审计、日志记录、数据校验、级联操作。
一、触发器核心概念
1. 触发时机与事件
- 触发事件 :
INSERT、UPDATE、DELETE。 - 触发时机 :
BEFORE:操作执行前触发(常用于数据校验、预处理)。AFTER:操作执行后触发(常用于日志记录、级联更新)。
- 触发对象 :
FOR EACH ROW(行级触发,每影响一行执行一次)。
2. 核心限制
- 不支持
SELECT语句(直接返回结果)。 - 不支持事务回滚(InnoDB 中,触发器执行失败会导致主事务回滚)。
- 一个表同一事件同一时机只能有一个触发器。
二、创建触发器(核心代码)
1. 基础语法
sql
DELIMITER // -- 修改结束符,避免与内部;冲突
CREATE TRIGGER 触发器名
{BEFORE | AFTER} {INSERT | UPDATE | DELETE}
ON 表名 FOR EACH ROW
BEGIN
-- 触发器体:SQL 语句集合
-- 引用旧数据: OLD (修改前的值)
-- 引用新数据: NEW (修改后的值)
END //
DELIMITER ; -- 恢复结束符
2. 场景一:创建只有一个执行语句的触发器
需求:在学生表插入数据时,自动记录操作日志到日志表。
sql
-- 1. 准备测试表
CREATE TABLE student (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(20) NOT NULL,
age INT NOT NULL
);
CREATE TABLE log (
id INT PRIMARY KEY AUTO_INCREMENT,
operation VARCHAR(20) NOT NULL,
operate_time DATETIME NOT NULL,
table_name VARCHAR(20) NOT NULL,
record_id INT NOT NULL
);
-- 2. 创建触发器
DELIMITER //
CREATE TRIGGER tr_student_insert
AFTER INSERT -- 插入操作后触发
ON student FOR EACH ROW
BEGIN
-- 记录日志:NEW.id 是刚插入的学生ID
INSERT INTO log(operation, operate_time, table_name, record_id)
VALUES ('INSERT', NOW(), 'student', NEW.id);
END //
DELIMITER ;
-- 3. 测试:插入一条学生数据
INSERT INTO student (name, age) VALUES ('张三', 18);
-- 4. 查看日志表:触发器自动插入了一条日志
SELECT * FROM log;
3. 场景二:创建有多个执行语句的触发器
需求:更新学生年龄时,记录新旧年龄对比日志。
sql
DELIMITER //
CREATE TRIGGER tr_student_update
AFTER UPDATE -- 更新操作后触发
ON student FOR EACH ROW
BEGIN
-- 多个执行语句用 ; 分隔
INSERT INTO log(operation, operate_time, table_name, record_id)
VALUES ('UPDATE', NOW(), 'student', OLD.id);
-- 记录新旧值差异
IF OLD.age != NEW.age THEN
INSERT INTO log(operation, operate_time, table_name, record_id)
VALUES (CONCAT('AGE_CHANGE:', OLD.age, '->', NEW.age), NOW(), 'student', NEW.id);
END IF;
END //
DELIMITER ;
-- 测试:修改年龄
UPDATE student SET age = 20 WHERE id = 1;
三、查看触发器
1. 利用 SHOW TRIGGERS 查看
sql
SHOW TRIGGERS;
-- 查看特定数据库的触发器
SHOW TRIGGERS FROM 数据库名;
说明:列出所有触发器的详细信息(名称、表、事件、时机)。
2. 在 triggers 表中查看详细信息
从系统数据库 information_schema 中查询,支持更精准的筛选:
sql
SELECT * FROM information_schema.TRIGGERS
WHERE TRIGGER_NAME = 'tr_student_insert' AND TRIGGER_SCHEMA = DATABASE();
关键字段:
EVENT_MANIPULATION:触发事件 (INSERT/UPDATE/DELETE)。ACTION_TIMING:触发时机 (BEFORE/AFTER)。ROUTINE_BODY:执行体语言 (SQL)。
四、触发器的使用(自动触发)
触发器无需手动调用,当触发事件发生时自动执行。
- INSERT :插入数据时,
NEW字段有效。 - UPDATE :更新数据时,
OLD和NEW字段有效。 - DELETE :删除数据时,
OLD字段有效。
五、删除触发器
sql
DROP TRIGGER [IF EXISTS] 触发器名;
-- 示例
DROP TRIGGER IF EXISTS tr_student_insert;
注意:删除触发器需具有
SUPER权限或相关权限。
六、触发器的注意事项(避坑核心)
1. 性能与维护
- 慎用触发器:触发器是隐式执行的,调试困难,会增加数据库开销。
- 避免级联循环:触发器内操作同一张表,可能导致死循环。
- 索引优化:触发器内的 SQL 语句必须优化,避免全表扫描。
2. 数据一致性
- InnoDB 事务 :在 InnoDB 中,触发器执行失败会导致主事务(如 INSERT)回滚 。
- 例:
INSERT学生成功,触发器INSERT日志失败 → 学生数据也会被回滚。
- 例:
- MyISAM 不支持事务:触发器执行失败,主操作可能已完成,数据不一致。
3. 数据迁移与备份
- 迁移数据库时,触发器不会自动复制,需要手动导出创建语句。
- 使用
mysqldump --triggers导出触发器。
4. 常见错误陷阱
- 在触发器中使用
SELECT ... INTO