你的位置:首页 > 数据库

[数据库]PL/SQL编程_触发器


触发器是一种特殊的存储过程,它在创建后就存储在数据库中。
触发器的特殊性在于它是建立在某个具体的表之上的,而且是自动激发执行的,如果用户在这个表上执行了某个DML操作( UPDATE 、INSERT 、DELETE ),触发器就被激发执行。
触发器常用于自动完成一些数据库的维护工作。
例如,触发器可以具有以下功能:
·可以对表自动进行复杂的安全性、完整性检查。
·可以在对表进行DML操作之前或之后进行其他处理。
·进行审计,可以对表上的操作进行跟踪。
·实现不同节点间数据库的同步更新。

触发器的使用
触发器是依附于某个具体的表的特殊存储过程,它在某个DML操作的激发下自动执行。
在创建触发器时应该仔细考虑如它的相关信息。
具体地说,应该考虑以下几个方面的问题:
1 )触发器应该建立在哪个表之上。
2 )触发器应该对什么样的DML操作进行相应。
3 )触发器在指定的DML操作之前激发还是在之后撤发。
4 )对每次DML相应一次,还是对受DML操作影响的每一行数据都响应一次。
在确定了触发器的实现细节后,现在,就可以创建触发器了。
创建触发器的语法格式为:
CREATE [OR REPLACE] TRIGGER 触发器名
BEFORE | AFTER | INSTEAD OF
DELETE | INSERT | UPDATE [OF 列名]
ON 表名
[FOR EACH ROW [WHEN 条件]]
BEGIN
PL/SQL语句;
END;
在创建触发器的语法结构中,用方括号限定的部分是可选的,可以根据需要选用。
创建触发器的命令是CREATE TRIGGER ,根据指定的名字创建一个触发器。
OR REPLACE子句的作用是如果已经存在同名的触发器,则删除它,并重新创建。
触发器可以是前激发的( BEFORE ),也可以是后激发的( AFTER )。
如果是前激发的,则触发器在DML语句执行之前激发。
如果是后激发的,则触发器在DML语句执行之后激发。
用BEFORE关键字创建的触发器是前激发的,用AFTER关键字创建的触发器是后激发的,这两个关键字只能使用其一。
INSTEAD OF子句仅用于视图上的触发器。
触发器可以被任何DML命令激发,包括INSERT 、DELETE和UPDATE 。
如果希望其中的一种、两种或三种命令能够激发该触发器,则可以指定它们之间的任意组合,两种不同命令之间用OR分开。
如果指定了UPDATE命令,还可以进一步指定当表中的哪个列受到UPDATE命令的影响时激发该触发器。
当在指定的表上执行指定的DML命令时,将会激发触发器,触发器将对这样的操作进行必要的响应。
触发器可能对每次单独的DML操作响应一次,也可能对每次DML操作所影响的每一行数据响应一次。
如果对每次单独的DML操作响应一次,触发器执行的次数与受影晌的行数无关,这样的触发器叫做语句级触发器
如果对受影响的每一行数据都响应一次,那么触发器执行的次数等于受影响的行数,这样的触发器叫做行触发器
FOR EACH ROW子句的作用是指定创建的触发器为行触发器。
如果没有这样的子句,则创建的触发器为语句级触发器。

由关键字BEGIN和END限定的部分是触发器的代码,也就是触发器被激发时所执行的代码。
代码的编写方法与普通PL/SQL块的编写方法相同。

在触发器中可以定义变量,也可以进行异常处理,如果发生异常,就执行相应的异常处理程序。

例如,下面创建的触发器是为了监视用户对表EMP中的数据所进行的删除操作。

如果有这样的访问,则打印相应的信息。

CREATE OR REPLACE TRIGGER tri_emp
AFTER DELETE
ON emp
BEGIN
DBMS_OUTPUT.PUT_LINE('正在对表emp进行删除操作');
END;

从触发器的执行情况可以看出,无论用户通过DELETE命令删除0行、1行或者多行数据,这个触发器只对每次DELETE操作激发一次,所以这是一个典型的语句级触发器。
如果一个触发器不再使用,那么可以删除它。

删除触发器的语法为:

DROP TRIGGER 触发器名;

例如,要删除刚才创建的触发器tri_emp,使用的语句为:

DROP TRIGGER tri_emp;

触发器的创建者和数据库管理员可以使触发器失效。

触发器失效后将暂时不起作用,直到再次使它有效。
使触发器失效的命令格式为:

ALTER TRIGGER 触发器名 DISABLE;

触发器失效后只是暂时不起作用,它仍然存在于数据库中,使用命令可以使它再次起作用。
使触发器再次有效的命令格式为:

ALTER TRIGGER 触发器名ENABLE;

例如,下面的两条命令先使触发器tri_emp 失效,然后使其再次有效:

ALTER TRIGGER tri_emp DISABLE;

ALTER TRIGGER tri_emp ENABLE;

语句级触发器

如果一个触发器在用户每次进行DML操作时被激发而且执行一次,而不管这个DML操作影响了多少行数据,这个触发器就是语句级触发器。
语句级触发器有前激发和后激发两种形式。

前激发触发器是在DML操作执行之前被激发执行,后激发触发器是在DML操作执行之后被激发执行。
无论是哪种形式,触发器都将执行一次。
例如,我们创建一个前激发触发器tri_emp,当用户对表EMP的DEPTNO列进行UPDATE操
作时该触发器将被激发。

创建该触发器的语句为:

CREATE OR REPLACE TRIGGER tri_emp
BEFORE UPDATE OF deptno
ON emp
BEGIN
DBMS_OUTPUT.PUT_LINE('正在对表emp进行修改DEPTNO列操作');
END;

从UPDATE语句的执行结果可以看出,实际受影响的有6行数据,但是触发器只执行了一次。
实际上不管这条语句影响了一行、两行还是多行,或者没有影响任何行,这个触发器都将在UPDATE语句执行之前被激发执行一次。
再考虑下面的UPDATE语句,相信会对语句级触发器的执行有更深的理解。
这次我们修改一个根本不存在的部门编号3 。

update emp set deptno=10 WHERE deptno=3;

如果更关心用户对表所实施的访问本身,而不是该次访问影响的数据行数,这时可以在表上创建语句级触发器。
在触发器中可以使用三个条件谓词,这三个谓词用来判断当前所执行的操作。

它们是:
INSERTING :如果激发触发器的操作是INSERT ,则结果为真,否则为假
UPDATING : 如果激发触发器的操作是UPDATE ,则结果为真,否则为假
DELETING :如果激发触发器的操作是DELETE ,则结果为真,否则为假
这三个条件谓词通常作为IF语句的条件,用来判断用户当前所进行的操作。
如果要对用户在表emp上进行的所有DML操作进行监视,可以在这个表上创建一个触发器,将用户的所有DML操作作为日志记录下来。
为此,我们先创建一个表emp_log ,它的结构及各列的意义如下所示。

列      类型     意义

oper_user  char(10)  执行DML操作的用户

oper_type  char(10)  DML操作的类型

oper_time  char(20)  执行DML操作的时间

然后,在表emp上创建一个后激发的触发器emp_dml_trg。

只要用户在表上进行DML操作,这个触发器就会将执行这个操作的用户以及操作类型和操作时间记录在表emp_log 中,而不管这样的操作影响了多少行数据。

CREATE OR REPLACE TRIGGER emp_dml_trg
AFTER INSERT OR UPDATE OR DELETE
ON emp
DECLARE
dml_type char(10);
BEGIN
if INSERTING then
dml_type := 'INSERT';
elsif UPDATING then
dml_type:='UPDATE';
elsif DELETING then
dml_type:='DELETE';
END if;
INSERT INTO emp_log
VALUES(user,dml_type, to_char(sysdate , 'yyyy-mm-dd hh:mi:ss' ));
END;

如果用户在表emp上进行了以下DML操作:

UPDATE emp set sal=sal+100;

DELETE FROM emp WHERE deptno=20;

那么这二个操作的信息都将被记录在表emp_log 中。