Oracle觸發器詳解

開發中確定會用到Oracle的觸發器,本文進行詳細講解。

這裏實例中用到的主要是Oracle中scott用戶下的emp以及dept表,數據以下

1、觸發器概念

一、概念:

觸發器的本質是一個存儲過程,顧名思義發生特定事件時Oracle會執行觸發器中的代碼。

細分它的組成能夠分爲3個部分:第一部分在什麼條件下觸發器會執行,即觸發器被觸發的事件。第二部分在什麼時間點執行觸發器

即觸發器的發生事件例如before,after。第三部分觸發器自身所要作的事情,就是觸發器被觸發之後具體想表達的事件,在begin和end

之間的sql。

2、觸發器的分類:

一、ddl觸發器:即執行ddl操做後所觸發的事件。

經常使用的ddl操做有:grant(受權),revoke(撤銷受權),create(建立),drop(刪除),alter(修改),comment(註釋),audit(審覈),rename(重命名)

在進行具體實例之前先來說解另外一個概念:oracle中的user和schema:

user:oracle中的用戶,擁有數據庫的對象以及對數據庫對象增刪改查的權限。schema:該用戶下全部數據庫對象的集合Collection.相似於生活中

房子schema和房子的擁有者user之間的關係,你是一個用戶user你能夠經過alter session查看別人的房子,可是你是否能夠改變房子中的傢俱,要看這個房子的擁有者是否grant你這個權限,除非你是全部房子的最高權限人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;

這裏看到在建立觸發器之後若是仍然使用ddl操做,便會報錯。

二、dml觸發器:基於dml操做的觸發器,細分又能夠分爲行觸發器和語句觸發器。

A、語句觸發器:dml操做可能會影響不少行,主要用於對數據的安全保護。

Example:禁止在週四,週五修改emp表數據

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;

這裏創建觸發器之後,當你想改變全部人的工資時就會出觸發器的錯誤,全部人的工資即表示會影響不少行。

B、行級觸發器:針對須要操做的那一行,有關鍵詞:for each row,用來

(1)實現數據的審計功能:

Example:作一個記錄刪除員工信息的表記錄被刪除員工的信息

這裏爲了避免改變oracle中emp表的數據,新建一個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;

這裏能夠看到在建立觸發器時,用到了for each row關鍵詞,:old.***用來表示更改之前的表中的數據,:new.***用來表示更改之後的數據,在刪除數據之後在日誌表就有對應的記錄。

(2)實現數據完整性:

Example:要求員工漲工資後,不能低於原來的工資,所漲工資也不能高於原來的50%。

這裏爲了避免改變oracle中emp表的數據,新建一個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';

 

 這裏能夠看到當改變數據時會觸發觸發器錯誤,對錶中某一個字段的修改用UPDATE OF便可,另外若是new和old在PLSQL塊的外部

即BEGIN外面不能夠加冒號。

(3)參照完整性:

Example:主要用於級聯更新,如更新dept表中的deptno時,emp表的deptno也更新。

這裏仍然新建2個表分別和emp表dept表的數據相同。

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;

這裏參照完整新指具備主從關係的多個表,當更新主表主鍵時須要更新從表的相關數據。

三、替代觸發器:

這裏先講另外一個概念:帶有with check option的視圖:

若是視圖的定義包括條件(如where子句)而且任何應用於該視圖的INSERT或UPDATE語句都應包括該條件,則必須使用WITH CHECK OPTION定義該視圖。

Example:

CREATE VIEW emp_view
(ename,empno)
AS SELECT ename,empno FROM emp 
WHERE deptno=20
WITH CHECK OPTION;

這裏有個條件部門號爲20,則任何修改這個視圖的語句都必須針對的是20號部門的員工。

繼續替代觸發器的概念:關鍵字insteadof,主要針對一些複雜的視圖,由於級聯表所產生的視圖不可使用update,insert,delete等關鍵字,沒有before,after等關鍵字,而且不能夠創建在with check option選項的視圖上,好比新建一個emp表和dept表的級聯視圖,則不能夠向其中添加數據,如今經過觸發器解決:

Example:

仍然新建2個表分別和emp表dept表的數據相同。

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受權才能創建視圖:

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;

這裏觸發器中當對視圖進行insert時,會對相應的emp_new 和dept_new進行修改,也就作到了對複雜視圖的修改。

四、系統觸發器:

顧名思義,由系統觸發器所觸發的事件,經常使用的系統事件startup,shutdown,db_roll_change,server error等。

Example:記錄啓動數據庫時的事件以及時間。

此處由於是系統觸發器,因此須要用sysdba的權限登錄。

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;

3、觸發器的綜合實例

Example:作一個日誌用來記錄scott用戶的一些操做:

首先在sysdba權限下創建日誌表,序列,觸發器:

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用戶下隨便建立個東西:

CREATE SEQUENCE my_seq;

回到sysdba權限下查看日誌表中是否有對應的記錄:

SELECT * FROM object_log;

發現有數據,說明一個日誌表成功作好,監視一些用戶操做的觸發器就作好了。

 

 

至此,觸發器所有說明完畢,不足之處還請評論說明,謝謝。                                                                                       2018-08-27    16:50:28

相關文章
相關標籤/搜索