Oracle数据库触发器是存储于数据库的命名PL/SQL语句块,当触发事件发生时他们会隐含的执行,执行触发器的活动被称为触发触发器。
特定用户在特定模式下,或者任何用户执行的ddl语句(如create或者alter),这种触发器经常被用于审计目的,并且专用于oracle DBA。可以记录各种模式修改,何时执行、以及那个用户执行的。
系统事件,如数据库启动或者关闭
用户事件,如登录或者注销。即可以定义一个触发器,在用户登录数据库时记录用户名和登录时间。
触发器相关视图:
创建触发器的通用语法:
create [or replace] trigger trigger_name {before|after} triggering_event on table_name [for each row] [follows another_trigger] [enable/disable] [when condition] declare declaration statements exception exception-bandling statements end ;
triggering_event 是针对数据库表的dml语句,table_name是与该触发器相关的数据库表的名称,子句for each row指定行触发器,只适用于所插入、修改或者删除的数行。when子句指定执行触发器时必须要满足的条件。 触发器的这部分称为触发器的头。
子句follows、enable、disable,它们是在oracle 11g的create or replace trigger
子句中加入的。在11之前需要使用alter trigger 命令来启用或者禁用触发器。
enable/disable子句指定触发器是在启用,还是禁用状态下被创建的。当触发器
被启用时,触发事件发生就会执行该触发器,类似的,当触发器被禁用时,触发
事件发生时也不会执行该触发器。
注意在默认情况下,不使用enable/disable子句创建触发器时,默认是启用的。
alter trigger trigger_name disable ; alter trigger trigger_name enable ;
使用follows选项,可以指定触发器被触发的顺序,这个选项适用于在相同表上所定义的,并且在相同时间点会执行的触发器。例如,如果在student表上定义两个触发器,并且在数据插入之前触发,如果自己不使用follows子句来指定执行顺序,oracle无法保证这些触发器始终按照相同的次序执行,注意,follows子句中所引用的触发器必须已经存在,并且编译成功。
注意:如果删除一个表,则在该表上所定义的数据库触发器也会被删除。
触发器可以被用于不同的目的:
1.执行不能通过使用完整性约束来定义的复杂业务规则
2.维护复杂的安全规则
3.自动生成衍生列的值
4.手机有关访问数据库表的统计信息
5.防止无效的事务
6.提供值审计
触发器的限制
1.触发器也许不会执行事务控制语句,例如commit、savepoint、rollback。当
触发器执行时,所有执行的操作会成为事务的一部分。当该事务被提交或者回滚
,触发器所执行的操作也会被提交或者回滚。这个规则的一个例外是包含自治事
务的触发器。
2.触发器调用的任何函数或者过程也许不会执行事务控制语句,除非包含自治事务
3.不允许在触发器体中声明long或者long raw变量
触发器的分类:before触发器和after触发器
before触发器
create or replace trigger student_bi before insert on student for each row declare v_student_id student.student_in%type ; begin select student_id_seq.nextval into v_student_id from dual ; :new.student_id := v_student_id ; :new.created_by := user ; :new.created_date := sysdate ; :new.modified_by := user ; :new.mocified_date := sysdate ; end ;
触发器包含伪记录:new,使得可以访问当前正在被处理的数据行,也就是说当前被插入student表的数据行。:new伪记录是一种triggering_table%type,所以在在当前情况下,它是student%type类型,为了访问伪记录:new的单独成员,需要使用点符号,也就是:new.created_by指的是:new伪记录的成员created_by,记录名和其成员之间使用点符号。
把序列值赋予student_id列的语句,通过pl/sql表达式访问序列是11G的新特性
在11G之前,只能通过查询访问序列。
如下情况,应该使用before触发器
1.当在insert或者update语句完成之前,触发器需要提供衍生列的值是。
如,enrollment表中final_grade列保存学生特定课程的最终成绩,这个值
来自于学生在整个课程期间的综合表现
2.当触发器决定insert、update或者delete语句是否应该允许完成的时候,如
当往instructor表插入一条记录,触发器可以验证给zip列提供的值是否有效,
或者也就是说,zipcode中是否存在对应整个值的记录
AFTER触发器
一个statistics表的结构如下所示
Name Null? Type ----------------------------------------- -------- ---------------------------- TABLE_NAME VARCHAR2(30) TRANSACTION_NAME VARCHAR2(10) TRANSACTION_USER VARCHAR2(30) TRANSACTION_DATE DATE
整个表用来收集数据库中不同表的统计信息,例如,可以记录谁从instractor表删除记录,以及删除的时间。
create or replace trigger instructor_aud after update or delete on instructor declare v_type varchar2(10); begin if updating then v_type := ‘UPDATE‘; elsif deleting then v_type := ‘DELETE‘; end if; update statistics set transaction_user = user, transaction_date = sysdate where table_name = ‘instructor‘ and transaction_name = v_type; if sql%notfound%type then insert into statistics values (‘instructor‘, v_type, user, sysdate); end if; end;
例子针对表instructor,触发器会在表update或者delete语句执行之后触发。
如下情况,应该使用after触发器
1.当触发器应该在dml语句执行之后被触发时。
2.当触发器执行before触发器中未指明的动作时。
详细操作见下篇.....