您的位置:首页 > 数据库 > Oracle

oracle事务嵌套研究

2008-04-29 10:17 696 查看
[align=left]l 事务嵌套测试案例[/align]
[align=left](1)首先,建立一个表:[/align]
[align=left]create table msg (msg varchar2(100));[/align]
[align=left](2)然后,建立子事务存储过程local。[/align]
create or replace procedure local is
cnt number := -1; -- Global variables
begin
select count(*) into cnt from msg;
dbms_output.put_line('local: # of rows is '||cnt);

insert into msg values ('New Record');
commit;
end;

(3)最后,用如下PL/SQL匿名块调用local;
declare
cnt number := -1;
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;

[align=left]运行结果(注意打开set serveroutput on)如下:[/align]
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-> 主匿名块最后’看到’了所有的记录.

PL/SQL 过程已成功完成。

(4)重建过程local,将commit改为rollback,如下:
create or replace procedure local is
cnt number := -1; -- Global variables
begin
select count(*) into cnt from msg;
dbms_output.put_line('local: # of rows is '||cnt);

insert into msg values ('New Record');
rollback;
end;

执行第(3)步的PL/SQL匿名块,
[align=left]运行结果(注意打开set serveroutput on)如下:[/align]
local: # of rows is 1
main: # of rows is 0-> 子程序把主匿名块的一条记录也rollback了,所以结果为0
local: # of rows is 0
local: # of rows is 1-> 主匿名块把自己的一条记录成功commt,子程序也可以看到
main: # of rows is 1

PL/SQL 过程已成功完成。

(5)重建过程local,将commit去掉,如下:
create or replace procedure local is
cnt number := -1; -- Global variables
begin
select count(*) into cnt from msg;
dbms_output.put_line('local: # of rows is '||cnt);

insert into msg values ('New Record');
end;

执行第(3)步的PL/SQL匿名块,
[align=left]运行结果(注意打开set serveroutput on)如下:[/align]
local: # of rows is 1-> 子程序看到主匿名块uncommited的一条记录
main: # of rows is 2-> 主匿名块可以看到主匿名块和子程序插入的uncommited记录
local: # of rows is 0-> 主匿名块把主匿名块和子程序插入的记录全部rollback
local: # of rows is 2-> 主匿名块把主匿名块和子程序插入的记录全部commit
main: # of rows is 3

PL/SQL 过程已成功完成。

l AUTONOMOUS TRANSACTION(自治事务)的介绍
AUTONOMOUS_TRANSACTION是指在function,procedure等subprograms中对事务进行自治管理,当在别的pl/sql block里去调用这些subprograms的时候这些subprograms并不随着父pl/sql block的失败而回滚,而是自己管自己commit。自治事务常用于写入LOG或TRAC信息便于查找错误。
自治事务(以下简称AT)是由主事务(以下简称MT)调用但是独立于MT的事务。在自治事务被调用执行时,MT被挂起,在自治事务内部,一系列的DML可以被执行并且commit或rollback. 自治事务防止嵌套提交,使事务在自己的事务区内提交或回滚不会影响其他的事务。由于自治事务的独立性,它的commit和rollback并不影响MT的执行效果。在自治事务执行结束后,主事务获得控制权,又可以继续执行了。
[align=left]实现自治事务的定义,只需下列PL/SQL的声明部分加上PRAGMA AUTONOMOUS_TRANSACTION 就可以了。[/align]
[align=left]1. 顶级的匿名PL/SQL块[/align]
[align=left]2. Functions 或 Procedure[/align]
[align=left]3. 触发器。[/align]
[align=left]比如:[/align]
[align=left]在一个独立的procedure中声明自治事务:[/align]
[align=left]CREATE OR REPLACE PROCEDURE [/align]
[align=left] Log_error(error_msg IN VARCHAR2(100))[/align]
[align=left]IS[/align]
[align=left] PRAGMA AUTONOMOUS_TRANSACTION;[/align]
[align=left]BEGIN[/align]
[align=left] Insert into Error_log values ( sysdate,error_msg);[/align]
[align=left] COMMIT;[/align]
[align=left]END;[/align]

现在用自治事务改写一下procedure local:
create or replace procedure local is
cnt number := -1; -- Global variables
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;

执行第(3)步的PL/SQL匿名块,
[align=left]运行结果(注意打开set serveroutput on)如下:[/align]
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 ->主匿名块最后’看到’了所有的记录.

PL/SQL 过程已成功完成。

l 结论:
从这个例子中我们看到,在没有自制事务的情况下,COMMIT和ROLLBACK的位置无论是在主匿名块中或者在子程序中,都会影响到整个当前事务. 如果子程序中有事务或有commit语句,那么是回滚不了的,否则可以回滚,因为事务只是回滚上一个committ或rollback之后的所有事务。
在使用自制事务的情况下, AT是独立的,在它执行时,MT被暂停了. AT的COMMIT,ROLLBACK并不影响MT的执行.
[align=left]运用AT时,有一些注意事项,简单列举如下:[/align]
[align=left]1. 在匿名PL/SQL块中,只有顶级的匿名PL/SQL块可以被设为AT[/align]
[align=left]2. Package 不能被声明为AT,只有package所拥有的function和procedure 才能声明为AT[/align]
[align=left]3. AT程序必须以commit 或rollback结尾,否则会产生Oracle错误ORA-06519: active autonomous transaction detected and rolled back[/align]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: