触发器简介
触发器的一个明显的特性就是不能被显式地调用,当触发事件发生时就会隐式地执行该触发器,且不接收参数。
触发器通常用来以下几个方面:
- 完成表的变更校验:当表数据发生INSERT、UPDATE或DELETE时,提供验证逻辑、检查完整性约束、记录日志等操作。
- 自动数据库维护:通过使用系统级的触发器,可以在数据库系统启动或退出时,通过触发器完成系统的初始化和清除操作。
- 控制数据库管理活动:可以使用触发器来精细地控制数据库管理活动,比如删除或修改表等操作,通过将逻辑放到这种触发器中,使得DDL操作的检查有了可保证性。
定义触发器
触发器语法如下:
CREATE [OR REPLACE] TRIGGER trigger_name
{BEFORE | AFTER | INSTEAD OF} triggering_event
[referencing_clause]
[WHEN trigger_condition]
[FOR EACH ROW]
trigger_body;
例子如下:
CREATE OR REPLACE TRIGGER t_verifysalary
BEFORE UPDATE ON emp --触发器作用的表对象以及触发的条件和触发的动作
FOR EACH ROW --行级别的触发器
WHEN(new.sal>old.sal) --触发器条件
DECLARE
v_sal NUMBER; --语句块的声明区
BEGIN
IF UPDATING ('sal') THEN --使用条件谓词判断是否是sal列被更新
v_sal := :NEW.sal - :OLD.sal; --记录工资的差异
DELETE FROM emp_history
WHERE empno = :OLD.empno; --删除emp_history中旧表记录
INSERT INTO emp_history --向表中插入新的记录
VALUES (:OLD.empno, :OLD.ename, :OLD.job, :OLD.mgr, :OLD.hiredate,
:OLD.sal, :OLD.comm, :OLD.deptno);
UPDATE emp_history --更新薪资值
SET sal = v_sal
WHERE empno = :NEW.empno;
END IF;
END;
在编写触发器时,要注意:
- 触发器的代码不能超过32KB,如果真的超过32KB,可以在触发器中使用CALL语句调用存储过程。
- 触发器代码只能包含SELECT、INSERT、UPDATE、DELETE,而不能包含DDL语句如CREATE、ALTER、DROP,也不能包含事务控制语句如COMMIT、ROLLBACK、SAVEPOINT。
- 尽管触发器可以实现较多的功能,但是不过过度使用触发器,否则会导致系统变得难以维护,比如连锁触发,比如别人不知道这里有个触发器等等。
触发器的分类
触发器根据其触发的时机与影响的行数,可以分为:
- 行触发器与语句触发器:行触发器会对数据库表中的每一行触发一次触发器代码,语句触发器则仅触发一次。
- BEFORE触发器与AFTER触发器:BEFORE触发器在触发的语句之前执行触发器操作,AFTER触发器则相反。
- INSTEAD OF触发器:是指不直接执行触发语句,一般用在视图更新的场合,比如在UPDATE一个视图时,替换掉原来的UPDATE语句,将语句分解为对多个数据表的操作。
- 系统事件触发器与用户事件触发器:发发生系统级的事件时,比如数据库启动,服务器错误消息事件触发时,执行系统事件触发器,在用户登录或退出,执行DDL或DML语句时,执行用户事件触发器。
如果根据触发器所创建的语句及所影响的对象的不同,触发器主要分为3大类:
- DML触发器
- 系统触发器
- 替代触发器