首页 > 开发 > 综合 > 正文

AUTONOMOUS TRANSACTION(自治事务)的介绍

2024-07-21 02:08:33
字体:
来源:转载
供稿:网友

 

 

在基于低版本的oracle做一些项目的过程中,有时会遇到一些头疼的问题.,比如想在执行当前一个由多个dml组成的transaction(事务)时,为每一步dml记录一些信息到跟踪表中,由于事务的原子性,这些跟踪信息的提交将决定于主事务的commit或rollback. 这样一来写程序的难度就增大了, 程序员不得不把这些跟踪信息记录到类似数组的结构中,然后在主事务结束后把它们存入跟踪表.哎,真是麻烦!

有没有一个简单的方法解决类似问题呢?

oracle8i的autonomous transaction(自治事务,以下at)是一个很好的回答。

at 是由主事务(以下mt)调用但是独立于它的事务。在at被调用执行时,mt被挂起,在at内部,一系列的dml可以被执行并且commit或rollback.

注意由于at的独立性,它的commit和rollback并不影响mt的执行效果。在at执行结束后,主事务获得控制权,又可以继续执行了。

见图1:

 

图1:

 

如何实现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的特性,一定能取得事倍功半的效果.

 

 

参考资料:

metalink.oracle.com

oracle8i manual

 
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表