#원자성

(on) 문장 수준의 원자성

Demo#1
{code:sqlborderStyle=solid}
-- 문장의 부수적인 결과(트리거)까지 문장의 일부분으로 간주
SQL> create table t2 ( cnt int );

Table created.

SQL> insert into t2 values ( 0 );

1 row created.

SQL> commit;

Commit complete.

SQL> create table t (x int check ( x>0 ) );

Table created.

SQL> create trigger t_trigger
2 before insert or delete on t for each row
3 begin
4 if ( inserting ) then
5 update t2 set cnt = cnt + 1;
6 else
7 update t2 set cnt = cnt - 1;
8 end if;
9 dbms_output.put_line( 'I fired and update ' || sql%rowcount || ' rows');
10 end;
11 /

Trigger created.

SQL> set serveroutput on;
SQL> insert into t values ( 1 );
I fired and update 1 rows

1 row created.

SQL> insert into t values ( -1 );
I fired and update 1 rows
insert into t values ( -1 )
*
ERROR at line 1:
ORA-02290: check constraint (SCOTT.SYS_C00158277) violated

SQL> select * from t2;

CNT



--
1

|
|{code:sql|borderStyle=solid}
Savepoint statement1;
  Insert into t values ( 1 );
If error then rollback to statement1;

Savepoint statement2;
  Insert into t values ( -1 );
If error then rollback to statement2;

-- Sybase/SQL Server 는 insert(t) 와 update(t2)가 별개임?
-- Oracle 은 만약 update(t2)의 트리거에 의해 delete(t3) 하는 경우(혹은 그 이상)에도 자연스럽게 원자성이 보장됨

|

(on) 프로시저 수준의 원자성

Demo#2
{code:sqlborderStyle=solid}
– PL/SQL 익명 블록을 문장으로 간주
SQL> create or replace procedure p
2 as
3 begin
4 insert into t values ( 1 );
5 insert into t values ( -1 );
6 end;
7 /

Procedure created.

SQL> delete from t;
I fired and update 1 rows

1 row deleted.

SQL> update t2 set cnt = 0;

1 row updated.

SQL> commit;

Commit complete.

SQL> select * from t;

no rows selected

SQL> select * from t2;

CNT



--
0

SQL> begin
2 p;
3 end;
4 /
I fired and update 1 rows
I fired and update 1 rows
begin
*
ERROR at line 1:
ORA-02290: check constraint (SCOTT.SYS_C00158277) violated
ORA-06512: at "SCOTT.P", line 5
ORA-06512: at line 2

SQL> select * from t;

no rows selected

SQL> select * from t2;

CNT



--
0

|
|{code:sql|borderStyle=solid}
Savepoint statement1;
  begin p; end;
If error then rollback to statement1;

|

(on) 프로시저 수준의 원자성, 다른 예제

Demo#3
{code:sqlborderStyle=solid}
– WHEN OTHERS 를 통해 어떤 오류가 발생 해도 무시 하도록 함 (ROLLBACK 안됨)
SQL> begin
2 p;
3 exception
4 when others then
5 dbms_output.put_line( 'Error!!!! '
sqlerrm );
6 end;
7 /
I fired and update 1 rows
I fired and update 1 rows
Error!!!! ORA-02290: check constraint (SCOTT.SYS_C00158277) violated

PL/SQL procedure successfully completed.

SQL> select * from t;

X



--
1

SQL> select * from t2;

CNT



--
1

|

h3. (on) WHEN OTHERS
||Demo#4||
|{code:sql|borderStyle=solid}
-- RAISE/RAISE_APPLICATION_ERROR를 통해 예외가 다시 발생하도록 처리하지 않은 WHEN OTHERS 예외 핸들러는 위험함 (저자는 버그로 봄)
-- 저자가 WHEN OTHER 를 디스 한 결과 아래와 같은 결과를 확인할 수 있음 (11gR1 계획 당시 WHEN OTHERS 를 제거를 제안 함)

SQL> alter session set PLSQL_Warnings = 'enable:all';

Session altered.

SQL> create or replace procedure some_proc( p_str in varchar2 )
  2  as
  3  begin
  4     dbms_output.put_line( p_str );
  5  exception
  6     when others
  7     then
  8        -- call some log_error() routine
  9        null;
 10  end;
 11  /

SP2-0804: Procedure created with compilation warnings

SQL> show errors procedure some_proc;
Errors for PROCEDURE SOME_PROC:

LINE/COL ERROR
-------- -----------------------------------------------------------------
1/1      PLW-05018: unit SOME_PROC omitted optional AUTHID clause;
         default value DEFINER used

6/9      PLW-06009: procedure "SOME_PROC" OTHERS handler does not end in
         RAISE or RAISE_APPLICATION_ERROR

|

(on) 프로시저 수준의 원자성, 또 다른 예제

Demo#5
{code:sqlborderStyle=solid}
– WHEN OTHERS 를 통해 ROLLBACK 하지만 나쁜 코드 (WHEN OTHERS 로 예외를 가로 챘고, 이미 제공 하는 기능을 명시적으로 코딩 함)
SQL> begin
2 savepoint sp;
3 p;
4 exception
5 when others then
6 rollback to sp;
7 dbms_output.put_line( 'Error!!!! '
sqlerrm );
8 end;
9 /
I fired and update 1 rows
I fired and update 1 rows
Error!!!! ORA-02290: check constraint (SCOTT.SYS_C00158277) violated

PL/SQL procedure successfully completed.

SQL> select * from t;

no rows selected

SQL> select * from t2;

CNT



--
0

|

h3. (on) 트랜잭션 수준의 원자성
h6. (1) 트랜잭션의 목적 : 데이터베이스를 일관적인 상태에서 다음의 일관적인 상태로 전환

h3. (on) DDL과 원자성
h6. (1) DDL 시작 시 묵시적으로 기존 트랜잭션을 COMMIT (WHY?)
h6. (2) DDL 성공시 COMMIT 실패시 ROLLBACK