触发器是什么?
触发器(Triggers)是数据库中的一种特殊对象,它们会在某些数据库事件发生时自动执行。触发器的主要作用是对表的操作(如INSERT
、UPDATE
、DELETE
)做出响应,并执行特定的操作。
触发器的操作
CREATE TRIGGER trigger_name
BEFORE/AFTER INSERT/UPDATE/DELETE ON table_name FOR EACH ROW
BEGIN-- 触发器执行的 SQL 语句
END;
触发器的组成部分:
-
trigger_name
:这是触发器的名称,用户可以根据需要自定义,以便标识和管理触发器。 -
BEFORE/AFTER
:指定触发器的触发时间。BEFORE
意味着在数据操作之前执行,AFTER
意味着在数据操作完成之后执行。- BEFORE:可以用于在插入、更新或删除之前进行数据验证或转换。
- AFTER:适合在数据操作后进行日志记录或数据同步等操作。
-
INSERT/UPDATE/DELETE
:这是触发器监视的操作类型。可以指定触发器在数据插入、更新或删除时触发执行。- INSERT:当表中有新记录插入时触发。
- UPDATE:当表中的记录被更新时触发。
- DELETE:当表中的记录被删除时触发。
-
table_name
:表示触发器所监视的表的名称,意味着该触发器将监听此表的指定操作。 -
FOR EACH ROW
:表示触发器会对表中受影响的每一行执行一次。如果操作影响了多行记录,那么触发器会逐行执行。 -
SQL 语句:触发器定义的核心逻辑部分,在触发事件发生时自动执行。可以是简单的 SQL 操作,也可以是复杂的逻辑操作。
触发器的应用场景:
- 数据验证:在数据插入或更新前,使用触发器验证数据的合法性。
- 自动计算字段:可以通过触发器在插入数据时自动计算或设置一些字段的值。
- 日志记录:当对表执行某些操作时,触发器可以自动记录日志。
- 数据同步:在主表的数据发生变化时,触发器可以自动更新或同步到其他表中。
注意事项:
- 触发器的频繁使用可能导致数据库的性能下降,尤其是在表的操作非常频繁的情况下。
- 复杂的触发器可能会导致维护难度增加,因此需要谨慎设计。
NEW 和 OLD 的含义:
-
NEW:
- 当执行
INSERT
或UPDATE
操作时,NEW 用于指代新插入或更新后的数据。 - 在
INSERT
触发器中,NEW 引用的是即将被插入的行数据。 - 在
UPDATE
触发器中,NEW 引用的是更新后的行数据。
- 当执行
-
OLD:
- 当执行
UPDATE
或DELETE
操作时,OLD 用于指代旧数据(即触发器前的数据)。 - 在
UPDATE
触发器中,OLD 引用的是更新之前的行数据。 - 在
DELETE
触发器中,OLD 引用的是即将被删除的行数据。
- 当执行
举例说明:
假设有一个表 my_table
,其中包含一个名为 quantity
的列。在这个表的 UPDATE
操作上创建一个触发器,用来将旧的 quantity
值加到新的 quantity
值中。代码如下:
CREATE TRIGGER my_trigger
BEFORE UPDATE ON my_table
FOR EACH ROW
BEGINSET NEW.quantity = NEW.quantity + OLD.quantity;
END;
解释:
OLD.quantity
引用的是更新之前该行的quantity
值。NEW.quantity
引用的是更新之后即将被保存到表中的quantity
值。- 在触发器中,新的
quantity
值会变成旧值和新值的总和。
注意事项:
- NEW 和 OLD 只能在适用于它们的操作中使用。例如,
INSERT
触发器中无法使用OLD
,因为插入时不存在旧数据,反之,DELETE
触发器中无法使用NEW
。 - 使用
BEFORE
和AFTER
时要注意,如果修改了NEW
的值,应该在BEFORE
触发器中进行,因为AFTER
触发器已经是操作后的阶段。
示例:
drop table if exists dept2;
create table dept2(id int primary key comment 'ID',name varchar(50) not null comment '部门名称'
) comment '部门';
INSERT INTo dept2(id, name) VALUES(1,'研发部'),(2,'市场部'),(3,'财务部'),(4,'销售部');drop table if exists oper_log;
create table oper_log(id bigint primary key auto_increment,table_name varchar(100) not null comment '操作的哪张表',oper_type varchar(100) not null comment '操作类型包括insert delete update',oper_time datetime not null comment '操作时间',oper_id bigint not null comment '操作的那行记录的id',oper_desc text comment '操作描述'
);/*触发器:需求:当向dept表当中insert插入数据之后(after),在oper_log表中记录日志
*/drop trigger if exists trigger_dept_insert;create trigger trigger_dept_insert
/* 触发规则 */
after insert on dept2 for each row
begin/* 一旦触发后发生的操作 */insert into oper_log(id, table_name, oper_type, oper_time, oper_id, oper_desc)values (null,'dept', 'insert', now(), new.id, concat('插入数据: id =', new.id , ', name = ', new.name));
end;
INSERT INTO dept2 (id, name) VALUES (5, '总经办');# SHOW CREATE TABLE dept;/*触发器
需求:更新dept表之后,在oper_log中记录日志*/drop trigger if exists trigger_dept_update;create trigger trigger_dept_update after update on dept2 for each row
begin/* 一旦触发后发生的操作 */insert into oper_log(id, table_name, oper_type, oper_time, oper_id, oper_desc)values (null,'dept', 'update', now(), new.id, concat('更新后: id = ', new.id , ', name = ', new.name,' 更新前: id = ',old.id, ' ,name = ', OLD.name));
end;/*触发器
需求:删除dept表的数据之后,在oper_log中记录日志*/
drop trigger if exists trigger_dept_delete;create trigger trigger_dept_delete after delete on dept2 for each row
begininsert into oper_log(id, table_name, oper_type, oper_time, oper_id, oper_desc)values (null,'dept', 'drop', now(), old.id, concat('删除数据: id =', old.id , ', name = ', old.name));
end;