posted by 구름너머 2005. 11. 17. 19:28

No. 12052

AUTONOMOUS TRANSACTION(8I NEW FEATURE)에 대한 소개
==================================================

autonomous transaction은 child transaction이라고도 불리우며 Oracle
8i부터 제공되는 새로운 기능이며 현재까지는 pl/sql을 통해서만 구현이
가능하지만 앞으로는 OCI까지 확장될 예정이다.

pl/sql routine의 declare section 중 어떠한 곳에서라도 아래의 progma
(compiler directive)를 지시함으로써 autonomous로 구분이 가능하다.

pragma AUTONOMOUS_TRANSACTION;

'pragma'는
1) top-level anonymous blocks
2) local, standalone or packaged functions and procedures
3) methods of object types
4) database triggers의 declare section 어디에서나 나타낼 수 있슴.

아래의 경우에는 사용이 불가능.

1) outside of a declase section
2) nested block의 declare section
3) package specification
4) package body 중 procedure나 function definition 외부
5) type body중 method definition의 외부

autonomous transaction(tx) 내에서 명시적으로 rollback이나 commit을
하여야 한다. 만일 이를 위반하였을 경우 main transcation 및 child
transaction 모두 error 발생과 함께 rollback이 되게 된다.

main transaction이 수행 중이고 child transaction이 아래의 상태의 경우 :

1) autonomous transcation으로 선언된 code unit의 declare section에서
기술된 statement가 수행 중인 동안 parent tx는 active로 남아있게 된다.

2) "begin" 이후의 첫 executable step을 만나게 되면 parent transaction은
유보되고 새로운 tx(child tx)가 시작된다.

3) 이 code unit은 normal하게 수행이 되나 tx context는 새로운 transaction로
설정된다.

4) autonomous code unit에서 commit 이나 rollback 이 수행되면 이
autonomous tx은 종료된다. 이 때까지 parent(main) tx는 계속 유보상태로
남아 있으며 autonomous unit에서 계속되는 operation이 있다면 새로운 tx이
시작된다.

5) autonomous code unit에서 exit를 하게 되면 transaction context는
parent로 전환이 된다.

transaction context의 변경은 session parameter에 영향을 주지 않는다.
따라서 parent transaction 에서 적용된 session parameter는 그대로 child
tx에서도 영향을 미치게 된다.
parent tx와 child tx는 서로 독립적이므로 lock 역시 공유하지 못한다.
만일 parent tx에서 점유된 lock을 child에서 소유하고자 한다면 dead lock
현상이 발생할 것이다. 이런 경우 ORA-60 이 발생되고 child tx는 자동적으로
rollback 된다.

<주의>
ORACLE 8.1.6 README에서는 분산 transaction에서 autonomous tx 사용 시
dead lock 발생 시 distributed lock timeout을 정상적으로 하지 못한다는
주의사항이 소개되고 있슴.

[예제]

create table test_lobs (c1 number,c2 clob);
create table msg (msg varchar2(120));

create or replace function getlen (p1 in clob,
p2 in number) return number as
pragma AUTONOMOUS_TRANSACTION;
len number;
buf varchar2(120);
tlen number;
begin
len := dbms_lob.getlength(p1);
if len != 0 then
dbms_lob.read(p1,len,1,buf);
dbms_output.put_line('Value: '||buf);
insert into msg values (buf);
commit;
end if;

select dbms_lob.getlength(c2) into tlen
from test_lobs where c1=p2;

dbms_output.put_line('Length selected from table is '||tlen);
return len;
end;

insert into test_lobs values (1,'Hello');
insert into test_lobs values (2,'The quick brown fox');
commit;

declare
cl1 clob;
cl2 clob;
ret number;
begin
select c2 into cl1 from test_lobs where c1 = 1 for update;
select c2 into cl2 from test_lobs where c1 = 2;
ret := getlen(cl1,1);
dbms_output.put_line('Length of first row is '||ret);
ret := getlen(cl2,2);
dbms_output.put_line('Length of second row is '||ret);
dbms_lob.writeappend(cl1,6,' there');
ret := getlen(cl1,1);
dbms_output.put_line('Length of first row is now '||ret);
end;