Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1035323
  • 博文数量: 243
  • 博客积分: 3053
  • 博客等级: 中校
  • 技术积分: 2975
  • 用 户 组: 普通用户
  • 注册时间: 2009-05-02 21:11
文章分类

全部博文(243)

文章存档

2013年(2)

2012年(20)

2011年(5)

2010年(114)

2009年(102)

我的朋友

分类: WINDOWS

2012-04-16 21:18:27

在基于低版本的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-0651Array: active autonomous transaction detected and rolled back
在程序开发时,如果充分运用autonomous transaction的特性,一定能取得事倍功半的效果.
阅读(1752) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

十七岁的回忆2012-04-17 15:37:03

请问,oracle自治事物,怎么带返回参数