<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    小菜毛毛技術(shù)分享

    與大家共同成長(zhǎng)

      BlogJava :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
      164 Posts :: 141 Stories :: 94 Comments :: 0 Trackbacks

    一則父子表下trigger拋出ORA-04091異常的變通處理

       trigger拋出ORA-04091異常,無非是當(dāng)前trigger下的事務(wù)access了一mutating table,比較常見的就是trigger訪問了自身上的表.在一個(gè)指定on delete cascade模式下的父子表中,trigger中如果有對(duì)其相關(guān)的父/子表的訪問,依然會(huì)拋出ORA-04091.這是比較隱性的.

       拿oracle的示例表emp和dept來做這個(gè)試驗(yàn).
       dept的表結(jié)構(gòu)如下:

    create table DEPT
        
    (DEPTNO NUMBER(2) not null primary key,
        
    DNAME  VARCHAR2(14),
        
    LOC    VARCHAR2(13));

        emp表結(jié)構(gòu)如下:

    create table EMP
        
    (EMPNO    NUMBER(4),
        
    ENAME    VARCHAR2(10),
        
    JOB      VARCHAR2(9),
        
    MGR      NUMBER(4),
        
    HIREDATE DATE,
        
    SAL      NUMBER(7,2),
        
    COMM     NUMBER(7,2),
        
    DEPTNO   NUMBER(2),
        
    foreign key(deptno) references dept(deptno) on delete cascade);

        emp和dept是一對(duì)父子表,關(guān)聯(lián)column為DEPTNO.

        接下來創(chuàng)建1個(gè) table:emp_log 和1個(gè)語句級(jí) trigger: emp_del_trg.取一個(gè)
    最簡(jiǎn)單的業(yè)務(wù)功能,emp_del_trg的作用就是當(dāng)表emp記錄被刪除的時(shí)候,觸發(fā)器將刪除的記錄的 EMPNO,DNAME和刪除時(shí)間寫入到emp_log中,當(dāng)子表依賴的父表相關(guān)記錄刪除的時(shí)候,emp_log不做處理.
        表emp_log的結(jié)構(gòu)如下:

    create table EMP_LOG
        
    (ENAME VARCHAR2(20),
        
    DNAME VARCHAR2(20),
        
    DATES DATE );

        觸發(fā)器trigger代碼如下:

    create or replace trigger emp_del_trg after delete on emp for each row
        
    begin
        
    insert into emp_log
        
    select :old.ename, dname, sysdate from dept where deptno = :old.deptno;
        
    end;

        來看看這個(gè)觸發(fā)器是否能正常工作,首先刪除emp的記錄.

    SQL> delete from emp where rownum<5;

    4 rows deleted

    SQL> select * from emp_log;

    ENAME DNAME DATES
    ——————– ——————– ———–
    SMITH RESEARCH 2008-7-1 18
    ALLEN SALES 2008-7-1 18
    WARD SALES 2008-7-1 18
    JONES RESEARCH 2008-7-1 18

    SQL> rollback;

    Rollback complete

        看似trigger工作正常,刪除dept的記錄呢?

    SQL> delete from dept where rownum<3;

    delete from dept

    ORA-04091: 表 KEVINYUAN.DEPT 發(fā)生了變化, 觸發(fā)器/函數(shù)不能讀它
    ORA-06512: 在 “KEVINYUAN.EMP_DEL_TRG”, line 2
    ORA-04088: 觸發(fā)器 ‘KEVINYUAN.EMP_DEL_TRG’ 執(zhí)行過程中出錯(cuò)

        ORA-04091錯(cuò)誤如約而至.不難解釋,因?yàn)楦缸颖碇付思?jí)聯(lián)刪除,刪除dept的記錄
    從而引起刪除emp表上的相應(yīng)數(shù)據(jù),然后觸發(fā)了emp_del_trg,由于trigger里有對(duì)dept的訪問,對(duì)當(dāng)前事務(wù)說,dept就是一個(gè)mutating table,這是不被允許的.

        如何來解決這個(gè)問題而實(shí)現(xiàn)這個(gè)簡(jiǎn)單的業(yè)務(wù)邏輯功能呢?當(dāng)然,從表結(jié)構(gòu)邏輯設(shè)計(jì)上來講,可以將dept表上的dname字段add到emp表,或者不要顯式的指定references,用程序來維護(hù)數(shù)據(jù)的完整性和約束,然后調(diào)整業(yè)務(wù)代碼.最直接的方法,在trigger中聲明一個(gè)ora-04091的exception,對(duì)此異常不做處理,也可完成目的。

        我們不妨做一下變通處理.將行級(jí)級(jí)觸發(fā)器變通成語句級(jí)觸發(fā)器.看下面的處理.

        1.創(chuàng)建一個(gè)package:emp_pkg .

    1. CREATE OR REPLACE PACKAGE emp_pkg AS
    2.     /* ----------------------------------
    3.        --Author:Kevin.yuan
    4.        --create_time: 2008 -07-01
    5.     ---------------------------------- */ 
    6.      TYPE crArray IS TABLE OF emp%ROWTYPE INDEX BY BINARY_INTEGER;
    7.      oldRows crArray; --accept the old values of emp
    8.      oldEmpty crArray;  --initialize values
    9.      END emp_pkg;

        2.創(chuàng)建一個(gè)語句級(jí)trigger,用來觸發(fā)trigger的時(shí)候清空初始化數(shù)據(jù).

    1. CREATE OR REPLACE TRIGGER emp_bd_st BEFORE DELETE ON emp
    2.     /*----------------------------------
    3.       Author:Kevin.yuan
    4.       create_time: 2008 -07-01
    5.     ---------------------------------- */ 
    6.      BEGIN
    7.        emp_pkg.oldRows := emp_pkg.oldEmpty;
    8.      END emp_bd_st;

        3.創(chuàng)建一個(gè)行級(jí)trigger:emp_d,問題的核心和關(guān)鍵就在這里,這個(gè)trigger
    并不參與業(yè)務(wù)邏輯,只是將觸發(fā)到的數(shù)據(jù)載入到emp_pkg.oldRows記錄表里面去.

    1. CREATE OR REPLACE TRIGGER emp_d AFTER DELETE ON emp FOR EACH ROW
    2.     /* ----------------------------------
    3.        --Author:Kevin.yuan
    4.        --create_time: 2008 -07-01
    5.     ---------------------------------- */ 
    6.     DECLARE
    7.     --ct is the position of the deleted records
    8.     ct INTEGER := emp_pkg.oldRows.COUNT + 1;
    9.     BEGIN
    10.      emp_pkg.oldRows(ct).ename := :OLD.ename;
    11.      emp_pkg.oldRows(ct).deptno := :OLD.deptno;
    12.     END emp_d;

        4.創(chuàng)建一個(gè)語句級(jí)trigger:emp_d_st,前面3步都是為這一步服務(wù)的,這一步
    真正參與業(yè)務(wù)邏輯處理.

    1. CREATE OR REPLACE TRIGGER emp_d_st AFTER DELETE ON emp
    2.     /* ----------------------------------
    3.        --Author:Kevin.yuan
    4.        --create_time: 2008 -07-01
    5.      ---------------------------------- */ 
    6.     DECLARE
    7.     BEGIN
    8.     FOR i IN 1 .. emp_pkg.oldRows.COUNT LOOP
    9.     INSERT INTO emp_log
    10.       (ename, dname, dates)
    11.       select emp_pkg.oldRows(i) .ename, dname, sysdate
    12.         from dept
    13.        WHERE deptno = emp_pkg.oldRows(i).deptno;
    14.     END LOOP;
    15.     END emp_d_st;

        來看一下變通后的觸發(fā)器是否滿足我們的業(yè)務(wù)要求:

    SQL> alter trigger emp_del_trg disable;

    Trigger altered

        刪除emp數(shù)據(jù)

    SQL> delete from emp where rownum<3;

    2 rows deleted

    SQL> select * from emp_log;

    ENAME DNAME DATES
    ——————– ——————– ———–
    SMITH RESEARCH 2008-7-1 19
    ALLEN SALES 2008-7-1 19

    SQL> rollback;

    Rollback complete

        刪除dept數(shù)據(jù).

    SQL> delete from dept;

    4 rows deleted

    SQL> select * from emp_log;

    ENAME DNAME DATES
    ——————– ——————– ———–

       至此,目的實(shí)現(xiàn).由于用了多于常規(guī)數(shù)量的觸發(fā)器,對(duì)系統(tǒng)性能會(huì)造成一定影響,而且,無疑會(huì)加重系統(tǒng)后期業(yè)務(wù)維護(hù)負(fù)擔(dān),因此,良好的數(shù)據(jù)庫邏輯設(shè)計(jì)和代碼編寫思路是很必要的,否則,只能走另外一些路徑,不過,這個(gè)由行級(jí)觸發(fā)器變語句級(jí)別觸發(fā)器的思路,還是有必要的,當(dāng)trigger中無法避免的需要access自身表的時(shí)候,這無疑是個(gè)可以借鑒的解決方案。

        THE END;




    另外一種方法:
    在declare中加入語句PRAGMA AUTONOMOUS_TRANSACTION;

    最后再提交操作方法,此方法的缺點(diǎn)是觸發(fā)器是一個(gè)事務(wù),外
    面程序又是一個(gè)事務(wù)
    posted on 2009-12-04 00:04 小菜毛毛 閱讀(775) 評(píng)論(0)  編輯  收藏 所屬分類: 數(shù)據(jù)庫
    主站蜘蛛池模板: 美女在线视频观看影院免费天天看 | 久久精品乱子伦免费| 亚洲av无码专区在线电影| 亚洲视频在线不卡| 亚洲色偷偷综合亚洲AVYP| 成人免费无码精品国产电影| 在线日本高清免费不卡| 久久性生大片免费观看性| 国产精品观看在线亚洲人成网| 亚洲喷奶水中文字幕电影| 久久国产精品亚洲一区二区| 久久影视国产亚洲| www.亚洲色图| 国产成人高清精品免费鸭子 | 全亚洲最新黄色特级网站 | 99热免费在线观看| 国产va免费观看| 国产成人va亚洲电影| 亚洲中文字幕久久无码| 亚洲国产精品无码久久久| 亚洲人成亚洲精品| 亚洲成在人线av| 国产亚洲精品a在线无码| 亚洲欭美日韩颜射在线二| 亚洲精品国产综合久久一线| 国产高清在线精品免费软件| 午夜成年女人毛片免费观看| 成人免费AA片在线观看| 67194国产精品免费观看| 人妻丰满熟妇无码区免费| 今天免费中文字幕视频| 国产色无码精品视频免费| 中文字幕无码一区二区免费| 精品乱子伦一区二区三区高清免费播放 | 亚洲AV无码一区二区三区久久精品| 中文字幕在线日亚洲9| 中文字幕在线观看亚洲视频| 亚洲成年网站在线观看| 亚洲一区二区观看播放| 亚洲日韩国产二区无码| 亚洲爆乳无码专区www|