Oracle Trigger 觸發器

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存儲過程、JAVA存儲過程或外部存儲過程實現。
那麼在觸發操作部分可直接使用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,AVG,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 觸發器名;


發佈了65 篇原創文章 · 獲贊 24 · 訪問量 41萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章