您的位置:首页 > 数据库 > Oracle

Oracle Trigger 触发器

2012-08-06 11:16 405 查看
Oracle Trigger

在Oracle8i之前,只允许给予表或者视图的的DML的操作,而从Oracle8i开始,不仅可以支持DML触发器,也允许给予系统事件和DDL的操作.

一、触发器的构成

触发器由触发事件、触发条件、触发操作三部分构成。

1、触发事件

指引起触发的sql语句、数据库事件或用户事件

包括:DML操作、启动关闭例程、oracle错误消息、用户登录断开会话、DML操作、DDL操作

2、触发条件

可选项,指使用when子句指定一个boolean表达式,当为true时,执行触发器相应的代码。

3、触发操作

指包含sql语句和其它执行代码的pl/sql块,不仅可以用pl/sql开发,也可以用java和c开发。

当触发条件为true时,会触发相应的代码,编写时需要注意以下几点:

1)、触发器代码大小不能超过32K,如果需要使用大量代码,应该建立存储过程,在触发器使用里调用。

2)、触发器只能包含select、insert、update、delete语句,不能包含ddl和事务控制语句。

二、触发器的分类

1.DML触发器(语句触发器、行级触发器)

2.事件触发器(系统事件触发器、客户事件触发器、DDL触发器)

3.替代触发器

三、DML触发器中,语句触发器与行级触发器的区别

1、行触发器有for each row子句,语句触发器没有for each row 子句。

2、行触发器,可以有when作为触发限制,可以使用new/old。语句触发器不能有when作为触发限制。

3、行触发器:对应DML语句所影响到的表中的每一行,触发器都要执行一遍。

4、语句触发:对应DML语句所影响到的表中的所有行,触发器只执行一遍。

四、DML触发器:指当执行DML语句时被隐含执行的触发器。

1、DML触发器应该具备得要素

建立DML触发器需要指定触发时机(before\after)、触发事件(insert\update\delete)、表名、触发器类型、触发器条件、触发操作。

1)、触发时机

before,在执行dml操作之前

after,在执行dml操作之后

2)、触发事件

用于指定导致触发器执行的DML操作,也即是insert,update,delete,触发事件可以单个可以多个。

3)、表名

DML触发器是针对特定表进行的,必须指定DMK操作对应的表。

4)、触发器类型

用于指定当触发事件发生之后,需要执行几次触发操作。语句触发器(默认)只执行一次,行触发器则每作用一行执行一次。

5)、触发条件

当为true时,执行触发器相应的代码,DML触发器只允许在行触发器上指定触发条件。

6)、触发操作

用于指定触发器执行代码。如果使用PL/SQL存储过程、J***A存储过程或外部存储过程实现。

那么在触发操作部分可直接使用call语句调用。如果使用PL/SQL匿名块,则按照

declare

--定义变量

begin

--编写pl/sql sql语句

exception

--异常处理

end;

2、DML触发器的触发顺序

1)、在单行数据上的触发顺序。

当针对同一表的相同DML操作而建立了多个DML触发器时,则触发器的顺序为

BEFORE语句触发器->BEFORE行级触发器->DML操作\->after行级触发器->after语句触发器。

2)、在多行数据上的触发顺序。

当针对某一表的相同DML操作而建立了多个DML触发器时,则触发器的顺序为

BEFORE语句触发器、

BEFORE行触发器

AFTER行触发器

BEFORE行触发器

AFTER行触发器

AFTER语句触发器

3、语句触发器

1)、语法

create or replace trigger trigger_name

timing event1 [or event2 or event2] on table_name

PL/SQL block;

其中timing指定触发时机(before/after),event1指定触发事件(insert\update\delete)

2)、before语句触发器

说明:为了确保DML操作在正常情况下执行。

create or replace trigger tri_tse

before insert or update or delete on emp

begin

if to_char(sysdate,'DY','nls_date_language=american') in ('SAT','SUN') then

raise_application_error(-20001,'不能在休息日改变雇员信息');

end if;

end;

3)、after语句触发器

说明:用于审计DML操作,或在DML操作之后执行汇总运算。

举例:

create or replace trigger tri_tru

after update on emp

declare

sqltxt ora_name_list_t;

vstmt varchar2(100);

m binary_integer;

begin

m:=ora_sql_txt(sqltxt);

for i in 1..m loop

vstmt:=vstmt || sqltxt(i);

end loop;

insert into ut_table(host,statement,exectime) values(sys_context('userenv','host'),vstmt,sysdate);

end;

--本触发器的作用将会记录更新的SQL语句插入到statemen字段中。

4)、使用条件谓词

当触发器中同时包含多个触发事件(insert\update\delete)时。为了在触发器代码中区分具体的触发事件

可以用下三个条件谓词:

inserting:代表insert语句触发事件

updating:代表update语句触发事件

deleting:代表delete语句触发事件

create or replace trigger tri_tse

before insert or update or delete on emp

begin

if to_char(sysdate,'DY','nls_date_language=american') in ('SAT','SUN') then

case when inserting then raise_application_error(-20001,'不能在休息日插入雇员信息');

when updating then raise_application_error(-20001,'不能在休息日更新雇员信息');

when deleting then raise_application_error(-20001,'不能在休息日删除雇员信息');

end if;

end;

4、行级触发器

执行DML操作时,每作用一行就触发一次触发器。

1)、语法

create [or replace] trigger trigger_name

timing event1 [or event2 or event3] on table_name

[referencing old as old | new as new]

for each row

[when condition]

PL/SQL block;

其中timing指定触发时机(before/after),event1指定触发事件(insert\update\delete)

referencing子句用于指定引用新、旧数据的方式,for each row表示建立行触发器;when子句用于指定触发条件。

2)、before行级触发器

说明:确保数据符合商业逻辑或企业规范。

例子:

Create or replace trigger tr_emp_sal

before update of sal on emp

for each row

begin

if :new.sal<:old.sal then

raise_application_error(-20010,'工资只涨不降');

end if;

end;

3)、after行级触发器

说明:为了审计数据的变化。

例子:

Create or replace trigger tr_sal_sal

after update of sal on emp

for each row

declare

v_temp int;

begin

select count(*) into v_temp from audit_emp_change where name=:old.ename;

if v_temp=0 then

insert into audit_emp_change values(:old.ename,:old.sal,:new.sal,sysdate);

else

update audit_emp_change set oldsal=:old.sal,newsal=:new.sal,time=sysdate where name=:old.ename;

end if;

end;

4)、限制行触发器

说明:当使用行触发器时,默认情况下会在每个被作用行上执行一次触发器代码,

为了使在特定条件下执行行触发器代码,就需要使用when子句对触发条件加以限制。

例子:

Create or replace trigger tr_sal_sal

after update of sal on emp

for each row

when (old.job='SALESMAN')

declare

v_temp int;

begin

select count(*) into v_temp from audit_emp_change where name=:old.ename;

if v_temp=0 then

insert into audit_emp_change values(:old.ename,:old.sal,:new.sal,sysdate);

else

update audit_emp_change set oldsal=:old.sal,newsal=:new.sal,time=sysdate where name=:old.ename;

end if;

end;

5)、DML触发器使用注意事项

编写DML触发器的时,触发器代码不能从触发器所对应的基表中读取数据。

例如,如果要要基于EMP表建立触发器,那么触发器代码不能包含对EMP表的查询操作。

此情况编译不会报错,执行会报错。

五、DML触发器的主要用途

说明:主要用于数据安全保护、数据审计、数据完整性、参照完整性、数据复制等功能。

1.控制数据安全

例如在非工作时间不能对EMP表做操作:

create or replace trigger tri_time

before insert or update or delete on emp

begin

if to_char(sysdate,'hh24') not between '9' and '17' then

raise_application_error(-20101,'非工作时间');

end if;

end;

--本触发器如果在非工作时间内将不予更新emp表

2.实现数据审查与统计

Oracle本身提供了数据审计功能:audit insert,update,delete on emp by access;

设置后会将sql操作的信息写入到数据字典中,但这种审计只审计SQL操作,而不记录数据变化,

如果要审计数据变化,如下例:

create or replace trigger tri_etr

after delete on emp for each row

begin

insert into emplog values(:old.ename,sysdate);

end;

--本触发器在emp表的记录被更新后,旧的记录插入到emplog表中。

3.实现数据完整性

数据完整性用约束实现性能是好的,例如alter table emp add constraint ck_sal check (sal>=800);

当约束无法实现特定的商业规则时可用触发器。

例如工资只升不降

create or replace trigger tri_salcheck

before update of sal on emp for each row

when (new.sal<old.sal or new sal>1.2*.old.sal)

begin

raise_application_error(-20931,'工资只升不降,且升福不能超过20%');

end;

4.实现参照完整性

说明:约束可以实现级联删除,就如这样

alter table emp add constraint fk_deptno foreign key(deptno) references dept(deptno) on delete cascade;

却不能实现级联更新,此时可以用到触发器:

create or replace trigger update_cascade

after update of deptno on dept for each row

begin

update emp set deptno=:new.deptno where deptno=:old.deptno;

end;

--参照完整性,利用触发器实现dept表的主键列和emp表的外部主键列的级联更新

六、INSTEAD OF触发器

1、概述

具有以下任一情况的视图不允许直接执行DML操作:

1)、具有集合操作符(union,union all,intersect,minus)

2)、具有分组函数(MIN,MAX,SUM,***G,COUNT等)

3)、具有group by、connext by、start with等子句;

4)、具有distinct关键字

5)、具有连接查询。

为了在具有以上情况的复杂视图上执行DML操作,必须要基于视图建立INSTEAD OF触发器。

另外,instead of触发器只适用于视图,不能指定before和after选项

2、INSTEAD OF触发器的使用

建一个复杂视图

create or replace view dept_emp as

select a.deptno,a.dname,a.empno,b.ename

from dept a,emp b

where a.deptno=b.deptno;

建立一个INSTEAD OF触发器

create or replace trigger tr_instead_of_dept_emp

INSTEAD OF insert on dept_emp for each row

declare

v_temp int;

begin

select count(*) into v_temp from dept where deptno=:new.deptno;

if v_temp=0 then

insert into dept(deptno,dname) values(:new.deptno,:new.dname);

end if;

select count(*) into v_temp from emp where empno=:new.empno;

if v_temp=0 then

insert into emp(empno,ename,deptno) values(:new.empno,:new.ename,:new.deptno);

end if;

end;

七、事件触发器

事件触发器是指基于Oracle事件(例如LOGON、STARTUP)所建立的触发器。通过使用事件触发器,提供了跟踪系统或数据库变化的机制。

常用的事件属性函数:

ora_client_ip_address 返回客户端的IP地址

ora_database_name 返回数据库名,类型是varchar2(50)

ora_dcs_cncrypted_password 返回DES加密后的用户口令

ora_dict_obj_name 返回DDL操作所对应的数据库对象名

ora_dict_obj_name_list 返回在事件中被修改的对象名列表

ora_dict_obj_owner 返回DDL操作所对应的对象的所有者名

ora_dict_obj_owner_list 返回在事件中被修改对象的所有者列表

ora_dict_obj_tpe 返回DDL操作所对应的数据对象类型

ora_grantee 返回授权事件的授权者

ora_instance_num 返回列程号

ora_is_alter_column 检测特定列是否被修改

ora_is_creating_nested_table 检测是否正在建立嵌套表

ora_is_drop_column 检测特定列是否被删除

ora_is_servererror 检测是否返回了特定Oracle错误

org_login_user 返回登录用户名,类型varchar2(30)

ora_sysevent 返回触发触发器的系统事件名

1、系统事件触发器

含义:是指由特定系统事件所触发的触发器,

包括4种事件:startup,shutdown,db_role_change,servererror

说明:系统事件触发器只能由SYS用户建立,并且shutdown abort命令不会触发shutdown事件。

例一(实例启动触发器)

create or replace trigger tri_startuplog

after startup on database --startup触发器只能用after

begin

insert into elog_table values(ora_sysevent,sysdate);

end;

例二(实例关闭触发器)

create or replace trigger tri_shutdownlog

before shutdown on database --shutdown触发器只能用before

begin

insert into elog_table values(ora_sysevent,sysdate); --获取系统事件名和操作事件

end;

2、客户事件触发器

含义:是指基于客户事件建立的触发器,客户事件是指与用户登陆、注销、DDL及DCL相关的事件

说明:

例一(登陆触发器)

create or replace trigger tri_logon

after logon on database --logon触发器只能用after

begin

insert into logon_table values(ora_login_user,sysdate,ora_client_ip_address); --获取用户名,操作事件,IP地址

end;

例二(退出触发器)

create or replace trigger tri_logoff

before logoff on database --logoff触发器只能用before

begin

insert into logon_table values(ora_login_user,sysdate,ora_client_ip_address); --获取用户名,操作事件,IP地址

end;

3、DDL触发器

含义:记载DDL事件的触发器(CREATE,ALTER,DROP等)

例一(DDL触发器)

create or replace trigger tri_ddl

after ddl on scott.schema --ddl触发器只能用after

begin

insert into tb_table values(ora_sysevent,ora_login_user,ora_dict_obj_owner,ora_dict_obj_name,ora_dict_obj_type,sysdate);

end;

--记录用户scott所做的操作DDL操作

八、管理触发器

1、查询触发器信息

select * from user_triggers where table_name='EMP'

2、激活、禁止触发器

禁止某个触发器:alter trigger 触发器名 disable;

禁止某个表的所有触发器:alter table disable emp all triggers;

激活某个触发器:alter trigger 触发器名 enable;

激活某个表的所有触发器:alter table enable emp all triggers;

3、重新编译

当使用alter table命令修改表结构时(例如增加删除列),会使得其触发器转为invalid状态,这样为了触发器继续生效,需要重新编译触发器。

alter trigger 触发器名 compile

4、删除触发器

drop trigger 触发器名;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: