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

          PL/SQL支持嵌套事務

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

          使用場景:
          當一個PL/SQL程序執行出錯 需要輸出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做一些項目的過程中,有時會遇到一些頭疼的問題.,比如想在執行當前一個由多個DML組成的transaction(事務)時,為每一步DML記錄一些信息到跟蹤表中,由于事務的原子性,這些跟蹤信息的提交將決定于主事務的commit或rollback. 這樣一來寫程序的難度就增大了, 程序員不得不把這些跟蹤信息記錄到類似數組的結構中,然后在主事務結束后把它們存入跟蹤表.哎,真是麻煩!

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

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

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

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

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

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

          1.  頂級的匿名PL/SQL塊

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

          3.  SQL Object Type的方法

          4.  觸發器。

            比如:

           在一個獨立的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是獨立的,在它執行時,MT被暫停了. AT的COMMIT,ROLLBACK并不影響MT的執行.

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

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

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

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

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

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


          評論

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

          2013-03-20 00:59 by
          但是
          主站蜘蛛池模板: 襄城县| 卢氏县| 佛坪县| 恩平市| 高阳县| 宁波市| 林周县| 甘泉县| 张家界市| 桃源县| 石城县| 葫芦岛市| 甘德县| 大埔县| 平湖市| 八宿县| 太谷县| 琼结县| 彰武县| 通江县| 新平| 开鲁县| 辉县市| 独山县| 清徐县| 祁东县| 亚东县| 庄河市| 辽阳县| 东明县| 三门峡市| 雅安市| 西充县| 康马县| 日喀则市| 永顺县| 禹州市| 阿鲁科尔沁旗| 罗甸县| 太湖县| 屏东市|