1. 程式人生 > >Oracle--觸發器

Oracle--觸發器

什麼是觸發器

觸發求器是一組完成特定功能的動作。這些動作由資料庫自動呼叫和執行。觸發器所執行的動作一般是一組DML操作。,

語句觸發器

語句觸發器的左右物件一般是資料表。其觸發動作是針對作用物件的Dml操作

建立語句觸發器

create trigger 觸發器名稱 on 作用物件
before/after 觸發動作
as
觸發器操作

create or replace trigger tr_insert_student
before insert
on students
begin
	if user!='admin' then 
		raise_application_error(-20001,'許可權不足,不能向表中插入資料');
	end if;
end;

raise_application_error(-20001,‘許可權不足,不能向表中插入資料’);丟擲錯誤提示,並禁止插入

觸發器的作用物件與觸發時機

Oracle中的觸發器可以建立在資料表或檢視之上

可以為表建立before和after型別的觸發器,但對檢視來說,不能為其建立before和after型別的觸發器

觸發器的觸發操作僅包含insert 和 update 。不能針對select操作建立觸發器。

多個啟用動作

一個觸發器可以建立在多個啟用動作之上,可以利用or關鍵字指定多個啟用動作

create or replace tirgger tr_student
before insert or update or delete
on students
begin
	if user!='admin' then 
		raise_application_error(-20001,'許可權不足,不能向資料表中插入資料');
	end if;
end;

觸發器謂詞

一個觸發器的啟用動作可能有多個,當需要分辨到底是什麼動作激活了觸發器。利用觸發器謂詞是一個很好的選擇。

觸發器謂詞有3種:inserting,updating,deleting

1.inserting,如果觸發語句是insert。為true否則為false
2、upodating ,如果是Update、為true
3、deleting。如果是delete、為true


create or replace trigger te_students_log
after insert or update or delete
on students
begin 
	if updating then
		insert into students_log values(user,'update',sysdate);
	end if;
	if inserting then
		insert into students_log values(user,'insert',sysdate);
	end if;
	if deleting then
		insert into students_log values(user,'delete',sysdate);
	end if;
end;

記錄使用者對資料表的操作日誌

如果提交所有資料修改,那麼表students_log的資料也將提交;而回滾表students的資料操作,那麼觸發器對students_log所做的資料操作也回滾

語句觸發器的作用級別為表,即無論觸發動作影響到多少記錄都執行一次觸發器

行觸發器

對於表students的修改,需要記錄其修改前的資料,即儲存歷史資料的需求,此時使用行觸發器

建立和使用行觸發器

行觸發器的建立語法與語句觸發器基本相同。只是需要為其新增for each row 選項。該選項正是行觸發器的標誌。

create or replace trigger tr_students_history
before update or delete 
on students
for each row
begin
	insert into students_history values(:old.students_id,:old.student_name,:old.students_age,:old.status,sysdate);
end	

:old是一個行型別變數,通過該變數可以引用行的各列。:old變數不能應用於insert操作型別的觸發器

行觸發器的變數引用

與:old變數對應的是:new 變數,:new用於引用新記錄

觸發器變數            insert   update   delete
:old                 不可用    可用      可用
:new                 可用      可用     不可用

create or replace trigger tr_students_upper
before update or insert
on students
for each row
begin
	:new.status :=upper(:new.status);
end;

在操作之前將新紀錄的status列轉換成大寫。其觸發時機不能是after

注意:

無論:old還是:new。改變其值就是改變了記憶體中記錄的對應列值,無論真實的dml語句是否涉及被更新的列,這些更改都會應用到資料表的修改之中

create or replace trigger tr_students_upper
before update or insert
on students
for each row
begin
	:new.student_age := 0;
	:new.status :=upper(:new.status);
end;


update students set status='new';

即使Update語句沒有涉及到列student_age。但是Oracle仍然將其更新為0

修改:old引用的值是無效動作,會報錯。

變數引用與referencing

可以在觸發器宣告時利用referencing 關鍵字指定變數以代替:old與:new引用

create or replace trigger trigger_students_insert
before insert
on students
referencing new as new_value
for each row
begin
	declare max_id number;
	begin
		select max(student_id) into max_id from students;
		:new_value.students_id :=max_id+1;
	end;
end;

多個觸發器的執行順序

當某個動作激活了多個觸發器時,這些觸發器將按照以下順序進行觸發:高級別>低級別。表觸發器先於行觸發器。如果級別相同,建立時間晚的先於建立時間早的觸發器

觸發器的條件限制

create or replace trigger tr_employee_cxl
before update
on tmp_employees
for each row
when (old.emplayee_age<18)
begin
	:new.status := 'cxl';
end;		

when (old.emplayee_age<18)置於when (old.emplayee_age<18)之後,表示只有行滿足employee_age小於18時,觸發器才會觸發。注意:限制條件必須用小括號擴起來,引用記錄使用old而非:old

instead of 觸發器

instead Of 觸發器則用於代替觸發動作,例如:insert動作的觸發器不再進行insert動作,而是轉而執行觸發器動作

建立和使用instead Of 觸發器

create or replace trigger tr_total_salary
instead of update 
on vw_total_salary
begin
	declare differ number;
	months number;
	begin
		select count(s.month) into months from salary s where s.employee_id=:old.employee_id;
		differ := (:new.total_salary-:old.total-salary)/months;
		update salary set salary=salary+differ where employee_id=:old.employee_id;
	end;
end;

起代替動作Update

instead Of 觸發器中的變數引用

instead Of 觸發器的觸發動作包括了Update、insert、delete。針對每一種動作的每行資料,instead Of觸發器都會執行一次。因此,instead Of觸發器是行級觸發器。但無須顯示宣告for each row。另外 ,instead Of觸發器雖可以直接引用原/新資料,但不能改變這些引用的值。

instead Of觸發器用於代替原動作,因此,原動作將不會被執行。對於Update來說,一旦new引用的值進行了修改,Oracle會嘗試將這種修改反映到資料庫中–即執行真正的Update動作。而這恰恰違背了instead Of觸發器的初衷。

系統事件與使用者事件觸發器

系統事件是指資料庫級別的動作所觸發的事件。這些事件主要包括資料庫啟動、資料庫關閉、系統錯誤等。針對系統事件所建立的觸發器稱為系統事件觸發器。

使用者事件是相對於使用者所執行的表(檢視)等Dml操作而言的。常見的使用者事件包括create事件、truncate事件、drop事件、alter事件、commit事件、rollback事件。針對使用者事件所建立的觸發器稱為使用者事件觸發器。

系統事件與使用者事件觸發器並非常用觸發器。

系統事件觸發器

記錄資料庫啟動時的時間

create or replace trigger tr_db_log
after startup
on database
begin
	insert into db_log values(user,'startup',sysdate);
end;

無需指定資料庫名稱,此時的資料庫即為觸發器所在的資料庫

資料庫關閉事件建立觸發器

create or replace trigger tr_db_shutdown
befor shutdown
on database
begin
	insert into db_log values(user,'shutdown',sysdate);
end;

觸發時機不能是資料庫啟動之前和資料庫關閉之後

使用者事件觸發器

一個使用者可以有資料庫中的多個物件,例如一個使用者擁有多個數據表和檢視。使用者事件觸發器的作用物件不是單個物件,而是使用者所擁有的所有物件的集合,即我們常說的schema。

以下動作的before和after時機均可建立觸發器

create建立物件
alter修改物件屬性
drop刪除物件
analyze分析資料表的統計資訊,以供優化器使用
associate statistics關聯統計資訊
disassociate statistics取消統計資訊的關聯
audit開啟物件或系統上的審計功能,以便記錄和跟蹤使用者操作
noaudit關閉物件或系統上的審計功能
comment為表或列添加註釋。這些註釋資訊可以通過資料字典獲取
grant為資料庫使用者授予許可權或角色
revoke收回資料庫使用者的許可權或角色
rename重新命名資料庫中的物件
truncate刪除表中所有記錄,並且不能回滾

以下事件只有before觸發器

logoff使用者退出資料庫

以下事件只有after觸發器

suspend當程式執行出現錯誤,並導致程式掛起


create or replace trigger tr_truncate_table
after truncate
on system.schema
begin
	insert into truncate_log values(ora_dict_obj_name,user,sysdate);
end;

on system.schema指定觸發器的作用物件是使用者system的所有物件;ora_dict_obj_name指定被刪除物件的物件名稱

觸發器的相關操作

禁用觸發器-disable

alter trigger trigger_name disable

啟用觸發器-enable

alter trigger trigger_name enable

在資料字典中檢視觸發器資訊

在Oracle資料庫中,與觸發器相關的檢視包括user_objects和user-triggers

select object_name,object_type,status from user_objects where lower(object_name) ='tr_students_upper';

select * from user_triggers

oracle 所允許的觸發器級聯(一個觸發器執行會啟用另一個觸發器…)資料為35,超過35會報錯。由於觸發器級聯的執行軌跡不易跟蹤,因此在開發時應儘量避免觸發器級聯的出現