这是一个非常实用的功能,特别用在记录错误日志同时要回滚主事务的时候,我们在实际开发中就是这么用的,感觉还是很方便的。转载一篇详细的介绍,感谢原作者。
在基于低版本的ORACLE做一些项目的过程中,有时会遇到一些头疼的问题.,比如想在执行当前一个由多个DML组成的transaction(事务)时,为每一步DML记录一些信息到跟踪表中,由于事务的原子性,这些跟踪信息的提交将决定于主事务的commit或rollback.这样一来写程序的难度就增大了,程序员不得不把这些跟踪信息记录到类似数组的结构中,然后在主事务结束后把它们存入跟踪表.哎,真是麻烦!
有没有一个简单的方法解决类似问题呢?
ORACLE8i的AUTONOMOUSTRANSACTION(自治事务,以下AT)是一个很好的回答。
AT是由主事务(以下MT)调用但是独立于它的事务。在AT被调用执行时,MT被挂起,在AT内部,一系列的DML可以被执行并且commit或rollback.
注意由于AT的独立性,它的commit和rollback并不影响MT的执行效果。在AT执行结束后,主事务获得控制权,又可以继续执行了。
如何实现AT的定义呢?我们来看一下它的语法。其实非常简单。
只需下列PL/SQL的声明部分加上PRAGMAAUTONOMOUS_TRANSACTION就可以了。
可以加自治事务的有:
1.顶级的匿名PL/SQL块
2.Functions或Procedure(独立声明或声明在package中都可)
3.SQLObjectType的方法
4.触发器。
比如:
在一个独立的procedure中声明AT
CREATEORREPLACEPROCEDURE
Log_error(error_msgINVARCHAR2(100))
IS
PRAGMAAUTONOMOUS_TRANSACTION;
BEGIN
InsertintoError_logvalues(sysdate,error_msg);
COMMIT;
END;
下面我们来看一个例子,(win2000advancedserver+oracle8.1.6,connectasscott)
建立一个表:
createtablemsg(msgvarchar2(120));
首先,用普通的事务写个匿名PL/SQL块:
declare
cntnumber:=-1;--}Globalvariables
procedurelocalis
begin
selectcount(*)intocntfrommsg;
dbms_output.put_line('local:#ofrowsis'||cnt);
insertintomsgvalues('NewRecord');
commit;
end;
begin
deletefrommsg;
commit;
insertintomsgvalues('Row1');
local;
selectcount(*)intocntfrommsg;
dbms_output.put_line('main:#ofrowsis'||cnt);
rollback;
local;
insertintomsgvalues('Row2');
commit;
local;
selectcount(*)intocntfrommsg;
dbms_output.put_line('main:#ofrowsis'||cnt);
end;
运行结果(注意打开serveroutput)
local:#ofrowsis1->子程序local中可以’看到’主匿名块中的uncommitted记录
main:#ofrowsis2->主匿名块可以’看到’2条记录(它们都是被localcommit掉的)
local:#ofrowsis2->子程序local首先’看到’2条记录,然后又commit了第三条记录
local:#ofrowsis4->子程序local又’看到’了新增加的记录(它们都是被localcommit掉的),然后又commit了第五条记录
main:#ofrowsis5->主匿名块最后’看到’了所有的记录.
从这个例子中,我们看到COMMIT和ROLLBACK的位置无论是在主匿名块中或者在子程序中,都会影响到整个当前事务.
现在用AT改写一下匿名块中的procedurelocal:
...
procedurelocalis
pragmaAUTONOMOUS_TRANSACTION;
begin
...
重新运行(注意打开serveroutput)
local:#ofrowsis0->子程序local中无法可以’看到’主匿名块中的uncommitted记录(因为它是独立的)
main:#ofrowsis2->主匿名块可以’看到’2条记录,但只有一条是被commited.
local:#ofrowsis1->子程序local中可以’看到’它前一次commit的记录,但是主匿名块中的记录已经被提前rollback了
local:#ofrowsis3->子程序local中可以’看到’3条记录包括主匿名块commit的记录
main:#ofrowsis4->主匿名块最后’看到’了所有的记录.
很明显,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:activeautonomoustransactiondetectedandrolledback
在程序开发时,如果充分运用AUTONOMOUSTRANSACTION的特性,一定能取得事倍功半的效果.
<!--EndFragment-->