Oracle中觸發(fā)器示例詳解
前言
在ORACLE系統(tǒng)里,觸發(fā)器類似過程和函數(shù),都有聲明,執(zhí)行和異常處理過程的PL/SQL塊。
觸發(fā)器類型
觸發(fā)器在數(shù)據(jù)庫里以獨(dú)立的對(duì)象存儲(chǔ),它與存儲(chǔ)過程和函數(shù)不同的是,存儲(chǔ)過程與函數(shù)需要用戶顯示調(diào)用才執(zhí)行,而觸發(fā)器是由一個(gè)事件來啟動(dòng)運(yùn)行。即觸發(fā)器是當(dāng)某個(gè)事件發(fā)生時(shí)自動(dòng)地隱式運(yùn)行。并且,觸發(fā)器不能接收參數(shù)。所以運(yùn)行觸發(fā)器就叫觸發(fā)或點(diǎn)火(firing)。ORACLE事件指的是對(duì)數(shù)據(jù)庫的表進(jìn)行的INSERT、UPDATE及DELETE操作或?qū)σ晥D進(jìn)行類似的操作。ORACLE將觸發(fā)器的功能擴(kuò)展到了觸發(fā)ORACLE,如數(shù)據(jù)庫的啟動(dòng)與關(guān)閉等。所以觸發(fā)器常用來完成由數(shù)據(jù)庫的完整性約束難以完成的復(fù)雜業(yè)務(wù)規(guī)則的約束,或用來監(jiān)視對(duì)數(shù)據(jù)庫的各種操作,實(shí)現(xiàn)審計(jì)的功能。
開發(fā)中肯定會(huì)用到Oracle的觸發(fā)器,本文進(jìn)行詳細(xì)講解。
這里實(shí)例中用到的主要是Oracle中scott用戶下的emp以及dept表,數(shù)據(jù)如下


一、觸發(fā)器概念
1、概念:
觸發(fā)器的本質(zhì)是一個(gè)存儲(chǔ)過程,顧名思義發(fā)生特定事件時(shí)Oracle會(huì)執(zhí)行觸發(fā)器中的代碼。細(xì)分它的組成可以分為3個(gè)部分:第一部分在什么條件下觸發(fā)器會(huì)執(zhí)行,即觸發(fā)器被觸發(fā)的事件。第二部分在什么時(shí)間點(diǎn)執(zhí)行觸發(fā)器即觸發(fā)器的發(fā)生事件例如before,after。第三部分觸發(fā)器自身所要做的事情,就是觸發(fā)器被觸發(fā)以后具體想表達(dá)的事件,在begin和end之間的sql。
二、觸發(fā)器的分類:
1、ddl觸發(fā)器:即執(zhí)行ddl操作后所觸發(fā)的事件。
常用的ddl操作有:grant(授權(quán)),revoke(撤銷授權(quán)),create(創(chuàng)建),drop(刪除),alter(修改),comment(注釋),audit(審核),rename(重命名)在進(jìn)行具體實(shí)例以前先來講解另一個(gè)概念:oracle中的user和schema:
user:oracle中的用戶,擁有數(shù)據(jù)庫的對(duì)象以及對(duì)數(shù)據(jù)庫對(duì)象增刪改查的權(quán)限。schema:該用戶下所有數(shù)據(jù)庫對(duì)象的集合Collection.類似于生活中房子schema和房子的擁有者user之間的關(guān)系,你是一個(gè)用戶user你可以通過alter session查看別人的房子,但是你是否可以改變房子中的家具,要看這個(gè)房子的擁有者是否grant你這個(gè)權(quán)限,除非你是所有房子的最高權(quán)限人dba。
ddl Example:禁止scott用戶的所有ddl操作
CREATE OR REPLACE TRIGGER scott_trigger BEFORE DDL ON SCHEMA BEGIN RAISE_APPLICATION_ERROR(-20008,'禁止scott用戶的所有ddl操作'); END;
create sequence myseq;

這里看到在創(chuàng)建觸發(fā)器以后如果仍然使用ddl操作,便會(huì)報(bào)錯(cuò)。
2、dml觸發(fā)器:基于dml操作的觸發(fā)器,細(xì)分又可以分為行觸發(fā)器和語句觸發(fā)器。
A、語句觸發(fā)器:dml操作可能會(huì)影響很多行,主要用于對(duì)數(shù)據(jù)的安全保護(hù)。
Example:禁止在周四,周五修改emp表數(shù)據(jù)
CREATE OR REPLACE TRIGGER emp_trigger
BEFORE UPDATE OR DELETE OR INSERT
ON emp
BEGIN
IF to_char(sysdate,'day') IN ('星期四','星期五') THEN
RAISE_APPLICATION_ERROR(-20008,'不允許在周四周五修改emp表');
END IF;
END;
update emp set sal=800;

這里建立觸發(fā)器以后,當(dāng)你想改變所有人的工資時(shí)就會(huì)出觸發(fā)器的錯(cuò)誤,所有人的工資即表示會(huì)影響很多行。
B、行級(jí)觸發(fā)器:針對(duì)需要操作的那一行,有關(guān)鍵詞:for each row,用來
(1)實(shí)現(xiàn)數(shù)據(jù)的審計(jì)功能:
Example:做一個(gè)記錄刪除員工信息的表記錄被刪除員工的信息
這里為了不改變oracle中emp表的數(shù)據(jù),新建一個(gè)emp_new表
create table emp_new as select * from emp;
create table emp_audit(name varchar2(10),delete_time Date);
CREATE OR REPLACE TRIGGER delete_trigger AFTER DELETE ON emp_new FOR EACH ROW BEGIN INSERT INTO emp_audit values(:old.ename,sysdate); END;
delete from emp_new where empno='7499';
select * from emp_audit;

這里可以看到在創(chuàng)建觸發(fā)器時(shí),用到了for each row關(guān)鍵詞,:old.***用來表示更改以前的表中的數(shù)據(jù),:new.***用來表示更改以后的數(shù)據(jù),在刪除數(shù)據(jù)以后在日志表就有對(duì)應(yīng)的記錄。
(2)實(shí)現(xiàn)數(shù)據(jù)完整性:
Example:要求員工漲工資后,不能低于原來的工資,所漲工資也不能高于原來的50%。
這里為了不改變oracle中emp表的數(shù)據(jù),新建一個(gè)emp_new表
create table emp_new as select * from emp;
CREATE OR REPLACE TRIGGER emp_trigger BEFORE UPDATE OF sal ON emp_new FOR EACH ROW WHEN (new.sal<old.sal OR new.sal>1.5*old.sal) BEGIN RAISE_APPLICATION_ERROR(-20008,'工資只增不降,且漲幅不可大于50%'); END;
update emp_new set sal = 1.6*sal where empno='7788';

這里可以看到當(dāng)改變數(shù)據(jù)時(shí)會(huì)觸發(fā)觸發(fā)器錯(cuò)誤,對(duì)表中某一個(gè)字段的修改用UPDATE OF即可,另外如果new和old在PLSQL塊的外部即BEGIN外面不可以加冒號(hào)。
(3)參照完整性:
Example:主要用于級(jí)聯(lián)更新,如更新dept表中的deptno時(shí),emp表的deptno也更新。
這里仍然新建2個(gè)表分別和emp表dept表的數(shù)據(jù)相同。
create table emp_new as select * from emp;
create table dept_new as select * from dept;
CREATE OR REPLACE TRIGGER cascade_trigger AFTER UPDATE OF deptno ON dept_new FOR EACH ROW BEGIN UPDATE emp_new SET deptno=:new.deptno WHERE deptno=:old.deptno; END;
update dept_new set deptno=15 where deptno=20;
select * from dept_new;

select * from emp_new;

這里參照完整新指具有主從關(guān)系的多個(gè)表,當(dāng)更新主表主鍵時(shí)需要更新從表的相關(guān)數(shù)據(jù)。
3、替代觸發(fā)器:
這里先講另一個(gè)概念:帶有with check option的視圖:
如果視圖的定義包括條件(如where子句)并且任何應(yīng)用于該視圖的INSERT或UPDATE語句都應(yīng)包括該條件,則必須使用WITH CHECK OPTION定義該視圖。
Example:
CREATE VIEW emp_view (ename,empno) AS SELECT ename,empno FROM emp WHERE deptno=20 WITH CHECK OPTION;
這里有個(gè)條件部門號(hào)為20,則任何修改這個(gè)視圖的語句都必須針對(duì)的是20號(hào)部門的員工。
繼續(xù)替代觸發(fā)器的概念:關(guān)鍵字insteadof,主要針對(duì)一些復(fù)雜的視圖,因?yàn)榧?jí)聯(lián)表所產(chǎn)生的視圖不可以使用update,insert,delete等關(guān)鍵字,沒有before,after等關(guān)鍵字,并且不可以建立在with check option選項(xiàng)的視圖上,比如新建一個(gè)emp表和dept表的級(jí)聯(lián)視圖,則不可以向其中添加數(shù)據(jù),現(xiàn)在通過觸發(fā)器解決:
Example:
仍然新建2個(gè)表分別和emp表dept表的數(shù)據(jù)相同。
CREATE TABLE emp_new AS SELECT * FROM emp; CREATE TABLE dept_new AS SELECT * FROM dept;
CREATE VIEW emp_dept AS SELECT d.deptno,d.dname,e.empno,e.ename FROM dept_new d,emp_new e WHERE d.deptno=e.deptno;
這里scott用戶需要先通過sysdba授權(quán)才能建立視圖:
grant create view to scott;
CREATE OR REPLACE TRIGGER insteadof_trigger INSTEAD OF INSERT ON emp_dept FOR EACH ROW DECLARE v_temp INT; BEGIN SELECT COUNT(*) INTO v_temp FROM dept_new WHERE deptno=:new.deptno; IF v_temp=0 THEN INSERT INTO dept_new(deptno,dname) VALUES(:new.deptno,:new.dname); END IF; SELECT COUNT(*) INTO v_temp FROM emp_new WHERE empno=:new.empno; IF v_temp=0 THEN INSERT INTO emp_new(deptno,empno,ename) VALUES(:new.deptno,:new.empno,:new.ename); END IF; END;
INSERT INTO emp_dept values(15,'HUMANRESOURCE',7999,'LEAF');
select * from emp_new;

select * from dept_new;

這里觸發(fā)器中當(dāng)對(duì)視圖進(jìn)行insert時(shí),會(huì)對(duì)相應(yīng)的emp_new 和dept_new進(jìn)行修改,也就做到了對(duì)復(fù)雜視圖的修改。
4、系統(tǒng)觸發(fā)器:顧名思義,由系統(tǒng)觸發(fā)器所觸發(fā)的事件,常用的系統(tǒng)事件startup,shutdown,db_roll_change,server error等。
Example:記錄啟動(dòng)數(shù)據(jù)庫時(shí)的事件以及時(shí)間。
此處因?yàn)槭窍到y(tǒng)觸發(fā)器,所以需要用sysdba的權(quán)限登陸。
CREATE TABLE event_table(event VARCHAR2(50),event_time DATE);
CREATE OR REPLACE TRIGGER event_trigger AFTER STARTUP ON DATABASE BEGIN INSERT INTO event_table VALUES(ora_sysevent,sysdate); END;

select * from event_table;

三、觸發(fā)器的綜合實(shí)例
Example:做一個(gè)日志用來記錄scott用戶的一些操作:
首先在sysdba權(quán)限下建立日志表,序列,觸發(fā)器:
CREATE TABLE object_log( logid NUMBER CONSTRAINT pk_logid PRIMARY KEY, operatedate DATE NOT NULL, objecttype VARCHAR2(50) NOT NULL, objectowner VARCHAR2(50) NOT NULL );
CREATE SEQUENCE obj_log_seq;
CREATE OR REPLACE TRIGGER object_trigger AFTER CREATE OR DROP OR ALTER ON DATABASE BEGIN INSERT INTO object_log VALUES(obj_log_seq.nextval,sysdate,ora_dict_obj_type,ora_dict_obj_owner); END;
在scott用戶下隨便創(chuàng)建個(gè)東西:
CREATE SEQUENCE my_seq;
回到sysdba權(quán)限下查看日志表中是否有對(duì)應(yīng)的記錄:
SELECT * FROM object_log;

發(fā)現(xiàn)有數(shù)據(jù),說明一個(gè)日志表成功做好,監(jiān)視一些用戶操作的觸發(fā)器就做好了。至此,觸發(fā)器全部說明完畢,不足之處還請(qǐng)?jiān)u論說明,謝謝。
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
Oracle中decode函數(shù)應(yīng)用示例詳解
Oracle?DECODE函數(shù)功能很強(qiáng),這篇文章主要給大家介紹了關(guān)于Oracle中decode函數(shù)應(yīng)用示例的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用oracle具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2024-05-05
oracle drop table(表)數(shù)據(jù)恢復(fù)方法
drop table刪除表以后怎樣可以恢復(fù),本文整理了一些操作語句,感興趣的朋友可以研究下,或許可以幫助到你2013-04-04
Oracle基礎(chǔ):程序中調(diào)用sqlplus的方式
今天小編就為大家分享一篇關(guān)于Oracle基礎(chǔ):程序中調(diào)用sqlplus的方式,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2018-12-12
ORA-06512數(shù)字或值錯(cuò)誤字符串緩沖區(qū)太小異常詳解
最近工作中遇到了Oracle: ORA-06512:字符串緩沖區(qū)太小,報(bào)錯(cuò)的意思很簡(jiǎn)單,字符串緩沖區(qū)小了,這篇文章主要給大家介紹了關(guān)于ORA-06512數(shù)字或值錯(cuò)誤字符串緩沖區(qū)太小異常的相關(guān)資料,需要的朋友可以參考下2023-01-01
Oracle7.X 回滾表空間數(shù)據(jù)文件誤刪除處理方法
Oracle7.X 回滾表空間數(shù)據(jù)文件誤刪除處理方法...2007-03-03
Oracle Portal及其門戶網(wǎng)站開發(fā)概述
Oracle Portal及其門戶網(wǎng)站開發(fā)概述...2007-03-03

