【DB筆試面試448】Oracle中有哪幾類觸發器?

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

♣          題目         部分

Oracle中有哪幾類觸發器?面試


     
♣          答案部分          



Oracle數據庫有4種觸發器,分別是DML、替代觸發器(INSTEAD OF觸發器)、DDL和系統觸發器,通常的應用系統中都使用到DML、替代觸發器,而DDL和系統觸發器是DBA管理數據庫用得比較多。下圖是Oracle觸發器的分類圖:算法

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

圖 3-2 Oracle中觸發器的分類
數據庫

觸發器(TRIGGER)的組成主要有如下幾部分:服務器

① 觸發事件:即在何種狀況下觸發TRIGGER。例如:DML語句(INSERT、UPDATE和DELETE語句對錶或視圖執行數據處理操做)、DDL語句(如CREATE、ALTER、DROP語句等在數據庫中建立、修改、刪除模式對象)、數據庫系統事件(如系統啓動或退出、異常錯誤)、用戶事件(如登陸或退出數據庫)。既能夠是單個觸發事件,也能夠是多個觸發事件的組合(只能使用OR邏輯組合,不能使用AND邏輯組合)。ide

② 觸發時間(觸發時機):即該TRIGGER是在觸發事件發生以前(BEFORE)仍是以後(AFTER)觸發,也就是觸發事件和該TRIGGER的操做順序。若是指定爲BEFORE,那麼表示在執行DML操做以前觸發,以便防止某些錯誤操做發生或實現某些業務規則;若是指定爲AFTER,那麼表示在執行DML操做以後觸發,以便記錄該操做或作某些過後處理。函數

③ 觸發器自己:即該TRIGGER被觸發以後的目的和意圖,正是觸發器自己要作的事情。例如:PL/SQL塊。性能

④ 觸發頻率:說明觸發器內定義的動做被執行的次數,分爲語句級(STATEMENT)觸發器和行級(ROW)觸發器。測試

a. 語句級(STATEMENT)觸發器:是指當某觸發事件發生時,該觸發器只執行一次;語句級觸發器不容許和WHEN子句一塊兒使用。this

b. 行級(ROW)觸發器:是指當某觸發事件發生時,對受到該操做影響的每一行數據,觸發器都單獨執行一次。加密

c. 當某操做隻影響到表中的一行數據時,語句級觸發器與行級觸發器的效果相同。

換句話說,語句級觸發器針對某一條語句只觸發一次,而行級觸發器則針對語句所影響的每一行都觸發一次。例如:某條UPDATE語句修改了表中的100行數據,那麼針對該UPDATE事件的語句級觸發器將被觸發一次,而行級觸發器將被觸發100次。

⑤ 觸發對象:包括表、視圖、用戶、數據庫。只有在這些對象上發生了符合觸發條件的觸發事件時,纔會執行觸發操做。

⑥ 觸發條件:由WHEN子句指定一個邏輯表達式。只有當該表達式的值爲TRUE時,遇到觸發事件纔會自動執行觸發器,使其執行觸發操做。

下面分別介紹這4類觸發器。

一、DML觸發器

DML觸發器由DML語句觸發,例如,INSERT、UPDATE和DELETE語句。針對全部的DML事件,按觸發的時間能夠將DML觸發器分爲BEFORE觸發器和AFTER觸發器,另外,DML觸發器也能夠分爲語句級觸發器與行級觸發器。

建立DML觸發器的通常語法以下所示:

CREATE [OR REPLACE] TRIGGER trigger_name

{BEFORE | AFTER }

{INSERT | DELETE | UPDATE [OF column [, column …]]}

ON [schema.] table_name

[REFERENCING {OLD [AS] old | NEW [AS] new| PARENT as parent}]

[FOR EACH ROW ]

[WHEN condition]

trigger_body;

其中:

l BEFORE和AFTER指出觸發器的觸發時機爲前觸發仍是後觸發,前觸發是在執行觸發事件以前觸發,後觸發是在執行觸發事件以後觸發當前所建立的觸發器。

l FOR EACH ROW選項說明觸發器爲行級觸發器。當省略FOR EACH ROW選項時,BEFORE和AFTER觸發器爲語句級觸發器,而INSTEAD OF觸發器則爲行級觸發器。

l REFERENCING子句說明相關名稱,在行級觸發器的PL/SQL塊和WHEN子句中可使用相關名稱參照當前的新、舊列值,默認的相關名稱分別爲OLD和NEW。在觸發器的PL/SQL塊中應用相關名稱時,必須在它們以前加冒號,但在WHEN子句中則不能加冒號。

l WHEN子句說明觸發約束條件。當Condition爲一個邏輯表達時,其中必須包含相關名稱,而不能包含查詢語句,也不能調用PL/SQL函數。WHEN子句指定的觸發約束條件只能用在BEFORE和AFTER行觸發器中,不能用在INSTEAD OF行觸發器和其它類型的觸發器中。

DML觸發器有以下幾種事件:

一、 INSERTING:當觸發事件是INSERT時,取值爲TRUE,不然爲FALSE。

二、 UPDATING[(column_1,column_2,…,column_x)]:當觸發事件是UPDATING時,若修改了column_x列,則取值爲TRUE,不然爲FALSE。其中,column_x是可選的。

三、 DELETING:當觸發事件是DELETE時,則取值爲TRUE,不然取值爲FALSE。

DML觸發器有以下的限制條件:

l CREATE TRIGGER語句文本的字符長度不能超過32KB

l 觸發器體內的SELECT語句只能爲SELECT … INTO … 結構,或者爲定義遊標所使用的SELECT語句

l 觸發器中不能使用事務控制語句COMMIT、ROLLBACK和SAVEPOINT

l 由觸發器所調用的存儲過程或函數也不能使用數據庫事務控制語句

l 觸發器中不能使用LONG、LONG RAW類型

l 觸發器內不能經過:NEW修改LOB列中的數據

l 觸發器最多能夠嵌套32層

當觸發器被觸發時,要使用被插入、更新或刪除的記錄中的列值,有時要使用操做前或操做後列的值,這個時候可使用:NEW或者:OLD來實現。其中,:NEW表示操做完成後列的值,而:OLD表示操做完成前列的值,以下表所示:

特性

INSERT

UPDATE

DELETE

:OLD

NULL

修改前的值

刪除前的值

:NEW

插入的值

修改後的值

NULL

:OLD表和:NEW表是內存中的兩個表,其結構和源表結構徹底一致。

(1) 當插入時,先將值插入到:NEW表中,在沒有控制的前提下才真正地插入到表中。

(2) 當刪除時,先將要刪除的數據移到:OLD表中,之前的表中的數據就沒有了。

(3) 當更新時,UPDATE XXX SET XXX=:NEW.XXX WHERE XXX=:OLD.XXX,WHERE條件是判斷已有的值,它就移動:OLD表中,SET是設置新的值先放到:NEW表中。

下面舉一個行級觸發器的例子。該觸發器能夠實現,當職工表SCOTT.EMP表被刪除一條記錄時,把被刪除記錄寫到職工表刪除日誌表中去,代碼以下所示:

--創建日誌表

CREATE TABLE SCOTT.EMP_HIS AS SELECT * FROM SCOTT.EMP WHERE 1=2;

--創建觸發器

CREATE OR REPLACE TRIGGER SCOTT.TR_DEL_EMP

   BEFORE DELETE --指定觸發時機爲刪除操做前觸發

   ON SCOTT.EMP

   FOR EACH ROW   --說明建立的是行級觸發器

BEGIN

   --將修改前數據插入到日誌記錄表EMP_HIS ,以供監督使用。

   INSERT INTO EMP_HIS(DEPTNO , EMPNO, ENAME , JOB ,MGR , SAL , COMM , HIREDATE )

   VALUES( :OLD.DEPTNO, :OLD.EMPNO, :OLD.ENAME , :OLD.JOB,:OLD.MGR, :OLD.SAL, :OLD.COMM, :OLD.HIREDATE );

END;

測試行級觸發器:

SYS@lhrdb> SELECT * FROM SCOTT.EMP_HIS;

no rows selected

SYS@lhrdb> DELETE SCOTT.EMP WHERE EMPNO=7788;

1 row deleted.

SYS@lhrdb> SELECT * FROM SCOTT.EMP_HIS;

     EMPNO ENAME      JOB              MGR HIREDATE                   SAL       COMM     DEPTNO

---------- ---------- --------- ---------- ------------------- ---------- ---------- ----------

      7788 SCOTT      ANALYST         7566 1987-04-19 00:00:00       3000                    20

下面再舉一個語句級觸發器的例子。

--創建日誌表

CREATE TABLE  SCOTT.MYLOG_LHR

      (CUR_USER VARCHAR2(30), CUR_DATE DATE, ACTION VARCHAR2(30));

--創建觸發器

CREATE OR REPLACE TRIGGER SCOTT.TRI_DML_EMP_LHR

  AFTER INSERT OR DELETE OR UPDATE ON SCOTT.EMP

BEGIN

  IF INSERTING THEN

    INSERT INTO SCOTT.MYLOG_LHR

      (CUR_USER, CUR_DATE, ACTION)

    VALUES

      (USER, SYSDATE, 'I');

  ELSIF DELETING THEN

    INSERT INTO SCOTT.MYLOG_LHR VALUES (USER, SYSDATE, 'D');

  ELSE

    INSERT INTO SCOTT.MYLOG_LHR VALUES (USER, SYSDATE, 'U');

  END IF;

END;

/

測試語句級觸發器:

SYS@lhrdb> SELECT * FROM SCOTT.MYLOG_LHR;

no rows selected

SYS@lhrdb> DELETE SCOTT.EMP WHERE ROWNUM<=1;

1 row deleted.

SYS@lhrdb> SELECT * FROM SCOTT.MYLOG_LHR;

CUR_USER                       CUR_DATE            ACTION

------------------------------ ------------------- ------------------------------

SYS                            2016-10-26 14:14:37 D

二、替代觸發器(INSTEAD OF觸發器)

因爲在Oracle裏,不能直接對由兩個以上的表創建的視圖進行操做,因此,給出了替代觸發器。能夠用替代觸發器解決視圖的多表更新問題,而且替代觸發器只能用於視圖。例如:針對INSERT事件的替代觸發器,它由INSERT語句觸發,當出現INSERT語句時,該語句不會被執行,而是執行替代觸發器中定義的語句。

建立替代觸發器的通常語法以下所示:

CREATE [OR REPLACE] TRIGGER trigger_name

INSTEAD OF

{INSERT | DELETE | UPDATE [OF column [, column …]]}

[OR {INSERT | DELETE | UPDATE [OF column [, column …]]}...]

ON [schema.] view_name --只能定義在視圖上

[REFERENCING {OLD [AS] old | NEW [AS] new| PARENT as parent}]

[FOR EACH ROW ] --由於INSTEAD OF觸發器只能在行級上觸發,因此沒有必要指定

[WHEN condition]

PL/SQL_block | CALL procedure_name;

其中,INSTEAD OF選項使Oracle激活觸發器,而不執行觸發事件。只能對視圖和對象視圖創建INSTEAD OF觸發器,而不能對錶、模式和數據庫創建INSTEAD OF觸發器。其它選項和DML觸發器的語法相同。

建立替代觸發器須要注意如下幾點內容:

① 只能建立在視圖上,而且該視圖沒有指定WITH CHECK OPTION選項。

② 不能指定BEFORE或AFTER選項。

③ FOR EACH ROW是可選的,即替代觸發器只能是行級觸發器,因此,沒有必要指定。

④ 沒有必要在針對一個表的視圖上建立替代觸發器,只要建立DML觸發器就能夠了。

⑤ 每個表和視圖只能有一個替代觸發器。

⑥ 替代觸發器被用於更新那些沒有辦法經過正常方式更新的視圖。

⑦ 替代觸發器的主要優勢就是可使不能更新的視圖支持更新。它支持多個表中數據的插入、更新和刪除操做。

下面舉一個視圖觸發器的例子。首先建立一個含有聚合函數的視圖,以下所示:

CREATE OR REPLACE VIEW SCOTT.VW_EMP_LHR AS

SELECT DEPTNO, COUNT(*) TOTAL_EMPLOYEER, SUM(SAL) TOTAL_SALARY

  FROM SCOTT.EMP

 GROUP BY DEPTNO;

在此視圖中,當直接刪除時會報錯,以下所示:

SYS@lhrdb> DELETE FROM SCOTT.VW_EMP_LHR WHERE DEPTNO=10;

DELETE FROM VW_EMP_LHR WHERE DEPTNO=10

            *

ERROR at line 1:

ORA-01732: data manipulation operation not legal on this view--此視圖的數據操縱操做非法

可是能夠經過建立替代觸發器來爲DELETE操做執行所需的處理,即刪除EMP表中全部基準行:

CREATE OR REPLACE TRIGGER SCOTT.EMP_VIEW_DELETE

  INSTEAD OF DELETE ON SCOTT.VW_EMP_LHR

  FOR EACH ROW

BEGIN

  DELETE FROM SCOTT.EMP WHERE DEPTNO = :OLD.DEPTNO;

END;

測試替代觸發器,以下所示:

SYS@lhrdb> DELETE FROM SCOTT.VW_EMP_LHR WHERE DEPTNO=10;

1 row deleted.

SYS@lhrdb> SELECT * FROM SCOTT.EMP WHERE  DEPTNO=10;

no rows selected

三、DDL觸發器和系統觸發器

因爲DDL觸發器和系統觸發器的建立語法很類似,因此,在此一併講解。其實,該部份內容涉及到面試中的一個問題,那就是,「如何監控會話的登陸登出狀況?」,答案就是使用審計或系統觸發器來實現。下面將詳細講解該部分的內容。

系統觸發器能夠在DDL或數據庫系統上被觸發。DDL指的是數據定義語言,如CREATE、ALTER及DROP等。而數據庫系統事件包括數據庫服務器的啓動或關閉,用戶的登陸與登出、數據庫服務錯誤等。

值得注意的一點是,隱含參數「_SYSTEM_TRIG_ENABLED」的默認值是TRUE,即容許DDL和系統觸發器。當設置隱含參數「_SYSTEM_TRIG_ENABLED」爲FALSE的時候,將禁用DDL和系統觸發器。

建立系統觸發器的通常語法以下所示:

CREATE OR REPLACE TRIGGER [sachema.]trigger_name

{BEFORE|AFTER}

{DDL_EVENT_LIST | DATABASE_EVENT_LIST}

ON { DATABASE | [schema.]SCHEMA }

[WHEN condition]

PL/SQL_block | CALL procedure_name;

其中:

l DDL_EVENT_LIST:一個或多個DDL事件,事件間用OR分開,能夠對全部DDL語句監控(直接寫DDL),也能夠對個別DDL語句監控。

l DATABASE_EVENT_LIST:一個或多個數據庫事件,事件之間用OR分開。

l ON:系統觸發器按照做用範圍,分爲SCHEMA觸發器和DATABASE觸發器。SCHEMA觸發器做用在單個用戶上,而DATABASE觸發器做用在整個數據庫全部用戶上。

l 對於WHEN子句後邊的內容須要由小括號括起來。

須要注意的是,系統觸發器既能夠創建在一個模式上,又能夠創建在整個數據庫上。當創建在模式(SCHEMA)之上時,只有模式所指定用戶的DDL操做和該用戶操做所致使的錯誤才能激活觸發器,默認時爲當前用戶模式。當創建在數據庫(DATABASE)之上時,該數據庫全部用戶的DDL操做和全部用戶操做所致使的錯誤,以及數據庫的啓動和關閉都可激活觸發器。要在數據庫之上創建觸發器,要求用戶具備ADMINISTER DATABASE TRIGGER權限或具備DBA角色。通常應該賦予的權限包括ADMINISTER DATABASE TRIGGER、ALTER ANY TRIGGER和CREATE ANY TRIGGER。

下表給出了系統觸發器的種類和事件出現的時機:

表 3-4系統觸發器的種類和事件

事件

容許的時機

說明

STARTUP

AFTER

啓動數據庫實例以後觸發

SHUTDOWN

BEFORE

關閉數據庫實例以前觸發(非正常關閉不觸發)

SERVERERROR

AFTER

數據庫服務器發生錯誤以後觸發。事件SERVERERROR能夠用於跟蹤數據庫中發生的錯誤。其錯誤代碼可使用觸發器內部的SERVER_ERROR屬性函數取出。該函數可讓用戶肯定堆棧中的錯誤碼。然而,該函數不能返回與該錯誤碼相關的錯誤信息,可是能夠經過使用系統函數DBMS_UTILITY.FORMAT_ERROR_STACK來解決。儘管觸發器自己不會引起錯誤,但藉助於該過程可使用PL/SQL來訪問錯誤堆棧

LOGON

AFTER

成功登陸鏈接到數據庫後觸發

LOGOFF

BEFORE

開始斷開數據庫鏈接以前觸發

CREATE

BEFORE、AFTER

在執行CREATE語句建立數據庫對象以前、以後觸發

DROP

BEFORE、AFTER

在執行DROP語句刪除數據庫對象以前、以後觸發

ALTER

BEFORE、AFTER

在執行ALTER語句更新數據庫對象以前、以後觸發

DDL

BEFORE、AFTER

在執行大多數DDL語句以前、以後觸發

GRANT

BEFORE、AFTER

執行GRANT語句授予權限以前、以後觸發

REVOKE

BEFORE、AFTER

執行REVOKE語句收權限以前、以後觸犯發

RENAME

BEFORE、AFTER

執行RENAME語句更改數據庫對象名稱以前、以後觸犯發

AUDIT/NOAUDIT

BEFORE、AFTER

執行AUDIT或NOAUDIT進行審計或中止審計以前、以後觸發

除DML語句的列屬性外,其他事件屬性值可經過調用Oracle定義的事件屬性函數來讀取,參考下表:

表 3-5事件屬性函數

函數名稱

同義詞

數據類型

說明

SYSEVENT

ORA_SYSEVENT

字符串

激活觸發器的事件名稱

INSTANCE_NUM

ORA_INSTANCE_NUM

數值

數據庫實例號

DATABASE_NAME

ORA_DATABASE_NAME

字符串

數據庫名稱

SERVER_ERROR(POSI)

ORA_SERVER_ERROR

數值

錯誤信息棧中POSI指定位置中的錯誤號

IS_SERVERERROR(ERR_NUMBER)

ORA_IS_SERVERERROR

布爾值

檢查ERR_NUMBER指定的錯誤號是否在錯誤信息棧中,若在則返回TRUE,不然返回FALSE。在觸發器內調用此函數能夠判斷是否發生指定的錯誤

LOGIN_USER

ORA_LOGIN_USER

字符串

登錄或註銷的用戶名稱

DICTIONARY_OBJ_TYPE

ORA_DICT_OBJ_TYPE

字符串

DDL語句所操做的數據庫對象類型

DICTIONARY_OBJ_NAME

ORA_DICT_OBJ_NAME

字符串

DDL語句所操做的數據庫對象名稱

DICTIONARY_OBJ_OWNER

ORA_DICT_OBJ_OWNER

字符串

DDL語句所操做的數據庫對象全部者名稱

DES_ENCRYPTED_PASSWORD

ORA_DES_ENCRYPTED_PASSWORD

字符串

正在建立或修改的通過DES算法加密的用戶口令

CLIENT_IP_ADDRESS

ORA_CLIENT_IP_ADDRESS

字符串

用於返回客戶端IP地址

上表中的函數和同義詞的對應關係能夠經過以下的SQL語句找到:

SELECT * FROM DBA_SYNONYMS D WHERE D.SYNONYM_NAME LIKE 'ORA%';

就像DML觸發器同樣,系統觸發器可使用WHEN子句來指定觸發器激活條件。關於系統觸發器須要瞭解如下幾點:

l STARTUP和SHUTDOWN觸發器不能帶有任何條件。

l SERVERERROR觸發器可使用ERRNO測試來檢查特定的錯誤。

l LOGON和LOGOFF觸發器可使用USERID或USERNAME測試來檢查用戶標識或用戶名。

l DDL觸發器能夠檢查正在修改對象的名稱、類型和操做類別。

DDL觸發器有不少實際用途,以下所示:

① 建表的同時創建公共同義詞

② 阻止非受權用戶的TRUNCATE操做

③ 記錄全部的DDL語句(包括SERVERERROR、GRANT、SHUTDDOWN、ALTER、REVOKE、DROP、TRUNCATE、COMMENT、STARTUP、AUDIT、CREATE、ANALYZE),以便查找責任人

④ 阻止DDL操做

⑤ 記錄服務器錯誤

⑥ 填充V$SESSION的CLIENT_INFO和CLIENT_IDENTIFIER列

⑦ 記錄用戶登陸數據庫失敗的詳細信息

⑧ 監控會話的登陸登出狀況

要禁用或啓用表的全部觸發器,可使用ALTER TABLE語句,以下所示:

ALTER TABLE T_20161026_LHR DISABLE ALL TRIGGERS; --禁用觸發器

ALTER TABLE T_20161026_LHR ENABLE ALL TRIGGERS; --啓用觸發器

將觸發器設置爲禁用或啓用使用ALTER TRIGGER語句,以下所示:

ALTER TRIGGER TRIGGER_NAME ENABLE;

ALTER TRIGGER TRIGGER_NAME DISABLE;

從新編譯觸發器的語句爲:

ALTER TRIGGER [SCHEMA.] TRIGGER_NAME COMPILE;

最後,介紹一下編寫觸發器的一些注意事項:

l 觸發器不接受參數。

l 一個表上最多能夠有12個觸發器,但同一時間、同一事件、同一類型的觸發器只能有一個。

l 在一個表上的觸發器越多,對在該表上的DML操做的性能影響就越大。

l 觸發器最大爲32KB。若確實須要,則能夠先創建存儲過程,而後在觸發器中調用存儲過程。

l 在觸發器的執行部分只能使用DML語句(例如SELECT、INSERT、UPDATE、DELETE等),不能使用DDL語句(例如CREATE、ALTER、DROP等)。

l 觸發器中不能包含事務控制語句(例如COMMIT、ROLLBACK、SAVEPOINT等)。由於觸發器是觸發語句的一部分,當觸發語句被提交、回退時,觸發器也被提交、回退了。

l 在觸發器主體中調用的任何存儲過程、函數,都不能使用事務控制語句。

l 在觸發器主體中不能聲明任何LONG或BLOB變量。

相關文章
相關標籤/搜索