关于Oracle AUTONOMOUS TRANSACTION(自治事务)的介绍(整理)
2015-12-10 14:53 silence_blog 阅读(555) 评论(0) 编辑 收藏 举报UTONOMOUS 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 varchar(100)) is pragma autonomous_transaction; begin insert into Error_log values(system,error_msg); commit; end;
下面我们来看一个例子:
建立一个表:
create table msg(ms varchar2(12));
由于下面会用到输出,而serveroutput默认为off状态,so
打开serveroutput输出:
set serveroutput on; --用于模块中的输出 dbms_output.put_line();
首先,用普通的事务写个匿名PL/Sql块:
declare cnt number:=-1; 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;
运行结果:
匿名块已完成
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又’看到’了新增加的记录,然后又commit了第五条记录
main: # of rows is: 5 -> 主匿名块最后’看到’了所有的记录.
上面的例子可以看出,commit和rollback的位置无论是在主匿名块中或者是在子程序中,都会影响到当前事务。
下面用AT改写一下匿名块中的procedure local:
…… procedure local is pragma AUTONOMOUS_TRANSACTION; begin ……
运行结果:
匿名块已完成
local: #of rows is: 0 ->子程序local中无法'看到'主匿名块中的uncommite记录(因为它是独立的)
main: # of rows is: 2 ->主匿名块可以'看到'2条记录,但只有一条是commit的。
local: #of rows is: 1 ->子程序local中可以'看到'1 条记录,是它之前commit的,主匿名块中的记录,已经被rollback
local: #of rows is: 3 ->子程序local中可以'看到'3条记录,其中2 条是被local commit的,一条是主匿名块commit的
main: # of rows is: 4 ->主匿名块最后'看到'了所有的记录.
显然,AT是独立的,在它执行时,MT被暂停了,AT的commit,rollback并不影响 MT的执行。
如果上面的匿名块不是很清楚,不能让你看明白程序的执行过程,你可以建立一个存储过程,将其包裹起来,然后单步调试跟踪运行,存储过程如下:
create or replace procedure test1 as cnt number:=-1; procedure local is
pragma autonomous_transaction;
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 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; end;
运用AT时,有一些注意事项,简单列举如下:
1.在匿名pl/sql块中,只有顶级的匿名pl/sql块可以被设为AT
2.如果AT视图访问MT控制的资源,可能有deallock发生。
3.package不能被声明为AT,只有package所拥有的function和procedure才能声明 AT
4.AT程序必须以commit或rollback结尾,否则会产生Oracle错误ORA-06519:active autonomous_transaction detected and rolled back
在程序开发中,如果充分运用autonomous transaction的特性,一定能取得事半功倍的效果。