一、触发器(trigger)
1、基本概念:触发器是一个特殊的存储过程,触发器的本质也是要写一段PL/SQL程序。数据库的触发器是一个与数据库中表相关联的、存储的PL/SQL程序。这意味着触发器是定义在表上面的程序。
2、作用:当每个特定的数据操作语句(插入insert、更新update、删除delet)注意这里没有查询语句,也就是说查询语句是没有触发器的)这些语句在指定表上发出是,Oracle自动执行触发器中定义的语句序列
创建触发器:
Createtrigger t_emp(触发器名)
after inserton emp(数据库中的表名)
declare
begin
dbms_output.put_line('成功插入新员工');
end;
/
3、触发器组成
1)触发事件引起触发器被触发的事件。 例如:DML语句(INSERT, UPDATE,DELETE语句)、DDL语句(如CREATE、ALTER、DROP语句在数据库中创建、修改、删除模式对象、数据库系统事件(如系统启动或退出、异常错误)、用户事件
2)触发时间 即TRIGGER 是在触发事件发生之前(BEFORE)还是之后(AFTER)触发
3)触发操作 触发器被触发之后需要做的事情
4)触发对象 包括表、视图、模式、数据库。
5)触发条件 WHEN子句指定一个逻辑表达式,当WHEN条件触发时才会执行触发器
6)触发频率 说明触发器内定义的动作被执行的次数。即语句级(STATEMENT)触发器和行级(ROW)触发器。
4、触发器的语法
create [or replace] trigger 触发器名称
{before |after}(这里before和after用来指明在操作前还是早做后调用这段程序)
{delete|insert|update[of 列名]}(指明做什么操作delete|insert|update[of列名],对于更新操作可以跟列名,表示该列发生变化触发该触发器)
on 表名(指明触发器创建在哪张表上)
[for each row [when(条件)]](行级触发器的关键字,如果出现这句话,说明该触发器是行级触发器,如果没有出现则触发器为语句级触发器)
PLSQL块
5、编写触发器需要注意一下几点
1)触发器不接受参数。
2) 一个表上最多可有12个触发器,但同一时间、同一事件、同一类型的触发器只能有一个。并各触发器之间不能有矛盾。
3)在一个表上的触发器越多,对在该表上的DML操作的性能影响就越大。
4)触发器最大为32KB。若确实需要,可以先建立过程,然后在触发器中用CALL语句进行调用
5)在触发器的执行部分只能用DML语句(SELECT、INSERT、UPDATE、DELETE),不能使用DDL语句(CREATE、ALTER、DROP)。
6)触发器中不能包含事务控制语句(COMMIT,ROLLBACK,SAVEPOINT)。因为触发器是触发语句的一部分,触发语句被提交、回退时,触发器也被提交、回退了。
7)在触发器主体中调用的任何过程、函数,都不能使用事务控制语句。
8)在触发器主体中不能申明任何Long和blob变量。新值new和旧值old也不能向表中的任何long和blob列。
9)不同类型的触发器(如DML触发器、INSTEAD OF触发器、系统触发器)的语法格式和作用有较大区别。
6、触发器的类型:
1)DML触发器(包括语句级触发器和行级触发器):在DML语句进行触发,可以在DML操作前或操作后进行触发,并且可以对每个行或语句操作上进行触发。
DML触发器的限制:1)CREATE TRIGGER语句文本的字符长度不能超过32KB;2)触发器体内的SELECT 语句只能为SELECT … INTO …结构,或者为定义游标所使用的SELECT 语句;3)触发器中不能使用数据库事务控制语句 COMMIT; ROLLBACK, SVAEPOINT 语句;由触发器所调用的过程或函数也不能使用数据库事务控制语句;4)触发器中不能使用LONG, LONG RAW 类型;5)触发器内可以参照LOB 类型列的列值,但不能通过 :NEW 修改LOB列中的数据;
【1、语句级触发器(针对表)指:在指定的操作语句操作之前或之后执行一次,不管这条语句影响多少行。
2、行级触发器(针对行)指:触发语句作用的每一条记录都被触发。在行级触发器中使用:old和:new伪记录变量,识别值的状态。:old表示操作该行之前,这一行的值;:new表示操作该行之后,这一样的值,两者代表同一条记录】
2)替代触发器:在ORACLE里,不能直接对由两个以上的表建立的视图进行操作。所以给出了替代触发器。它就是ORACLE 8专门为进行视图操作的一种处理方法。
替代触发器需要注意:1)只能被创建在视图上,并且该视图没有指定WITH CHECK OPTION选项;2)不能指定BEFORE 或 AFTER选项;3)FOR EACH ROW子可是可选的,即INSTEAD OF触发器只能在行级上触发、或只能是行级触发器,没有必要指定;4)没有必要在针对一个表的视图上创建INSTEAD OF触发器,只要创建DML触发器就可以了。
3)系统触发器:ORACLE 8i 提供了第三种类型的触发器叫系统触发器。它可以在ORACLE数据库系统的事件中进行触发,如ORACLE系统的启动与关闭等。
7、删除触发器
1)语句的方式删除触发器:DROP TRIGGER trigger_name;如果是通过软件来操作数据库,也可以去软件里面直接删除触发器;另外直接删除表或试图是,建立在这些对象上的触发器也随之删除。
2)当删除其他用户模式中的触发器名称,需要具有DROP ANY TRIGGER系统权限,当删除建立在数据库上的触发器时,用户需要具有ADMINISTERDATABASE TRIGGER系统权限。
8、触发器应用场景:
1)进行复杂的安全性检查;例如非工作时间禁止程序员操作数据库用触发器来实现安全性的检查
案例:禁止在非工作时间插入数据
/*1.周末: to_char(sysdate,'day') in ('星期六',‘星期日’)
2.上班前,下班后: */
create or replace trigger securityemp
before insert
on emp
begin
if to_char(sysdate,'day') in ('星期六', '星期日') or
to_number(to_char(sysdate,'hh24')) not between 9 and 18(对between...and取反表示九点前,十八点后) then
raise_application_error(-20001,'禁止在非工作时间插入新员工');(raise是表示从数据库中抛出一个错误,所以不可以使用raise; raise_application_error错误代码要在错误区间上区间范围是-20000到-29999)
end if;
end;
/
2)数据确认;比如说实现涨工资,涨后的工资应该高于涨前的工资,不然就不能称之为涨工资,而是扣工资。所以要确认涨后工资大于涨前工资才进行操作。这就是做数据确认。
案例:涨工资
create or replace trigger check_salary(创建或者替换一个触发器)
before update on emp
for each row(行级触发器语句)
begin
if :new.sal(涨后薪水)<:old.sal(涨前薪水) then
raise_application_error(-20002,'涨后薪水不能少于涨前薪水。 涨后薪水为:'||:new.sal ||'涨前的薪水:'||:old.sal);
end if;
end;
/
3)实现审计功能;就是说跟踪表上所作的数据操作,比如某人在某张表上做了什么。(在Oracle数据库中审计功能已经被单独的实现,在Oracle数据库中有5种数据库审计方法,触发器只是其中的一种)
案例:给员工涨工资,涨后工资薪水高于6000块时,审计该员工信息(审计功能)
创建表用户保存审计信息
create table audit_info(
information varchar2(200));/*用来保存审计信息*/
create or replace trigger do_audit_emp_salary(此触发器基于值的审计)
after update on emp
for each row
begin
if :new.sal>6000 then
insert into audit_info values(:new.empno||' '||:new.ename||' '||:new.sal);
end if;
end;
/
4)完成数据的备份和同步;例如有两个数据库一个为主数据库,另一个为从数据库(备份数据库)。我们在主数据库中建立一张表,在表中对数据进行操作并针对某些操作定义触发器。当满足触发器的条件之后可以自动将表中的数据从主数据库中备份到从数据库中
案例:当给员工涨完工资后,自动备份新的工资资料到备份表中(例子在同一个数据库,用两张表上进行演示)
create or replace trigger trigger_sync_salary
after update on emp
for each row
begin
update emp_back set sal=:new.sal where empno=:new.empbo;
end;
/