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