posts - 56, comments - 54, trackbacks - 0, articles - 4
             ::  ::  :: 聯系 :: 聚合  :: 管理

          PL/SQL支持嵌套事務

          Posted on 2006-01-27 16:20 Terry的Blog 閱讀(2258) 評論(1)  編輯  收藏 所屬分類: oracle

          使用場景:
          當一個PL/SQL程序執(zhí)行出錯 需要輸出log信息到數據庫表中的時候 就會遇到這個難題.
          log的內容要提交到表中 但是前面出錯的內容卻不能提交.雖然我們可以在出錯時先Rollback 等log好了
          再commit.但是這樣畢竟比較麻煩.實際上PL/SQL本身支持嵌套事務.
          看下面的小例子:
          CREATE OR REPLACE procedure Test1
          as
          PRAGMA AUTONOMOUS_TRANSACTION; -- 關鍵就是這句
          begin
          --set transaction read write;
          insert into aaa values(1,4,7);
          commit;
          end;
          /

          CREATE OR REPLACE procedure Test2
          as
          begin
          --set transaction read write;
          insert into aaa values(2,5,8);
          Test1;
          insert into aaa values(3,6,9);
          rollback;
          end;
          /
          當execute Test2完了時在AAA表中插入了一行(1,4,7)。

          --------------------------------------------------------------------------------------------------------------------------
          理論知識:
          AUTONOMOUS TRANSACTION(自治事務)的介紹:

          在基于低版本的ORACLE做一些項目的過程中,有時會遇到一些頭疼的問題.,比如想在執(zhí)行當前一個由多個DML組成的transaction(事務)時,為每一步DML記錄一些信息到跟蹤表中,由于事務的原子性,這些跟蹤信息的提交將決定于主事務的commit或rollback. 這樣一來寫程序的難度就增大了, 程序員不得不把這些跟蹤信息記錄到類似數組的結構中,然后在主事務結束后把它們存入跟蹤表.哎,真是麻煩!

          有沒有一個簡單的方法解決類似問題呢?

          ORACLE8i的AUTONOMOUS TRANSACTION(自治事務,以下AT)是一個很好的回答。

          AT 是由主事務(以下MT)調用但是獨立于它的事務。在AT被調用執(zhí)行時,MT被掛起,在AT內部,一系列的DML可以被執(zhí)行并且commit或rollback.

          注意由于AT的獨立性,它的commit和rollback并不影響MT的執(zhí)行效果。在AT執(zhí)行結束后,主事務獲得控制權,又可以繼續(xù)執(zhí)行了。

          如何實現AT的定義呢?我們來看一下它的語法。其實非常簡單。

          只需下列PL/SQL的聲明部分加上PRAGMA AUTONOMOUS_TRANSACTION 就可以了。

          1.  頂級的匿名PL/SQL塊

          2.  Functions 或 Procedure(獨立聲明或聲明在package中都可)

          3.  SQL Object Type的方法

          4.  觸發(fā)器。

            比如:

           在一個獨立的procedure中聲明AT

          CREATE OR REPLACE PROCEDURE

             Log_error(error_msg IN VARCHAR2(100))

          IS

             PRAGMA AUTONOMOUS_TRANSACTION;

          BEGIN

             Insert into Error_log values ( sysdate,error_msg);

             COMMIT;

          END;

          下面我們來看一個例子,(win2000 advanced server + oracle8.1.6 , connect as scott)

          建立一個表:

          create table msg (msg varchar2(120));

          首先,用普通的事務寫個匿名PL/SQL塊:

           declare

             cnt  number := -1;   --} Global variables

             procedure local is

             begin

                select count(*) into cnt from msg;

                dbms_output.put_line('local: # of rows is '||cnt);

                insert into msg values ('New Record');

                commit;

             end;

           

             begin

                delete from msg ;

                commit;

                insert into msg values ('Row 1');

                local;

                select count(*) into cnt from msg;

                dbms_output.put_line('main: # of rows is '||cnt);

                rollback;

                local;

                insert into msg values ('Row 2');

                commit;

                local;

                select count(*) into cnt from msg;

                dbms_output.put_line('main: # of rows is '||cnt);

             end;

          運行結果(注意打開serveroutput)

          local: # of rows is 1   -> 子程序local中可以’看到’主匿名塊中的uncommitted記錄

          main: # of rows is 2    -> 主匿名塊可以’看到’2條記錄(它們都是被local commit掉的)

          local: # of rows is 2   -> 子程序local首先’看到’2條記錄,然后又commit了第三條記錄

          local: # of rows is 4   -> 子程序local又’看到’了新增加的記錄(它們都是被local commit掉的),然后又commit了第五條記錄

          main: # of rows is 5    -> 主匿名塊最后’看到’了所有的記錄.

          從這個例子中,我們看到COMMIT和ROLLBACK的位置無論是在主匿名塊中或者在子程序中,都會影響到整個當前事務.

          現在用AT改寫一下匿名塊中的procedure local:

          ...

             procedure local is

                pragma AUTONOMOUS_TRANSACTION;

             begin

          ...

          重新運行(注意打開serveroutput)

          local: # of rows is 0   -> 子程序local中無法可以’看到’主匿名塊中的uncommitted記錄 (因為它是獨立的)

          main: # of rows is 2    -> 主匿名塊可以’看到’2條記錄,但只有一條是被commited.

          local: # of rows is 1   -> 子程序local中可以’看到’它前一次commit的記錄,但是主匿名塊中的記錄已經被提前rollback了

          local: # of rows is 3   -> 子程序local 中可以’看到’3條記錄包括主匿名塊commit的記錄

          main: # of rows is 4    ->主匿名塊最后’看到’了所有的記錄.

          很明顯,AT是獨立的,在它執(zhí)行時,MT被暫停了. AT的COMMIT,ROLLBACK并不影響MT的執(zhí)行.

          運用AT時,有一些注意事項,簡單列舉如下:

          1.     在匿名PL/SQL塊中,只有頂級的匿名PL/SQL塊可以被設為AT

          2.     如果AT試圖訪問被MT控制的資源,可能有deadlock發(fā)生.

          3.     Package 不能被聲明為AT,只有package所擁有的function和procedure 才能聲明為AT

          4.     AT程序必須以commit 或rollback結尾,否則會產生Oracle錯誤ORA-06519: active autonomous transaction detected and rolled back

          在程序開發(fā)時,如果充分運用AUTONOMOUS TRANSACTION的特性,一定能取得事倍功半的效果.


          評論

          # re: PL/SQL支持嵌套事務  回復  更多評論   

          2013-03-20 00:59 by
          但是
          主站蜘蛛池模板: 余干县| 陇南市| 通渭县| 华容县| 余江县| 永新县| 呼图壁县| 定日县| 木兰县| 东阿县| 修文县| 蒲江县| 河源市| 达州市| 酒泉市| 九寨沟县| 鹰潭市| 平昌县| 濮阳市| 文成县| 峨边| 中山市| 台安县| 时尚| 蓝山县| 安吉县| 屯昌县| 北安市| 大方县| 海宁市| 贺州市| 永康市| 潮州市| 福海县| 龙井市| 蒙阴县| 江津市| 芒康县| 堆龙德庆县| 兴化市| 瑞昌市|