-- 1. Procedure가 또 다른 Procedure를 중첩해서 호출할때.
------------------------------------------------------------------------------
CREATE TABLE TEST1
( ID NUMBER NOT NULL
, NAME VARCHAR2(10));
DELETE FROM TEST1;
COMMIT;
CREATE OR REPLACE PROCEDURE PROC01(P_NUM IN NUMBER)
IS
V_ID TEST1.ID%TYPE;
BEGIN
SELECT NVL(MAX(ID), 0) + 1 INTO V_ID FROM TEST1;
INSERT INTO TEST1 VALUES (V_ID, 'PROC01 : ' || V_ID);
DBMS_OUTPUT.PUT_LINE('PROC01 BEFORE 1');
PROC02(P_NUM);
DBMS_OUTPUT.PUT_LINE('PROC01 AFTER 2');
COMMIT; -- 1. 이 구문이 PROC02 호출 이전에 있다면 PROC02에서 ROLLBACK이 발생해도 PROC01는 영향받지 않고 COMMIT된 정보 유지된다.
-- ROLLBACK; -- 2. PROC02 COMMIT되고 여기에 PROC01에서 ROLLBACK처리해도 두번의 Insert 구문이 모두 COMMIT되어 있다.
-- 3. 중첩호출되는 PROCEDURE에서 COMMIT이 되면 MAIN PROCEDURE에서 ROLLBACK해도 중첩호출된 PROCEDURE에서 처리된 값은 COMMIT유지된다.
-- 4. 중첩호출되는 PROCEDURE에서 COMMIT이나 ROLLBACK이 명시되지 않으면 MAIN PROCEDURE에서의 명시한 COMMIT/ROLLBACK으로 일괄 적용된다.
-- 결국, PROCEDURE를 Application에서 호출하고 그 Transcation 결과가 All Or Nothing 되도록 하기위해서는
-- 호출되는 개별 PROCEDURE에서 COMMIT/ROLLBACK 명시하지 않고 Application에서 COMMIT/ROLLBACK 명시하면 된다.
DBMS_OUTPUT.PUT_LINE('PROC01 COMMIT 3');
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
DBMS_OUTPUT.PUT_LINE('PROC01 ERROR MESSAGE : ' || SQLERRM);
RAISE_APPLICATION_ERROR(-20000, 'PROC01 ERROR MESSAGE : ' || SQLERRM);
END;
/
CREATE OR REPLACE PROCEDURE PROC02(P_NUM IN NUMBER)
IS
V_ID TEST1.ID%TYPE;
V_NUM NUMBER;
BEGIN
SELECT NVL(MAX(ID), 0) + 1 INTO V_ID FROM TEST1;
INSERT INTO TEST1 VALUES (V_ID, 'PROC02 : ' || V_ID);
DBMS_OUTPUT.PUT_LINE(' PROC02 BEFORE 1');
V_NUM := 1 / P_NUM;
DBMS_OUTPUT.PUT_LINE(' PROC02 AFTER 2');
COMMIT;
DBMS_OUTPUT.PUT_LINE(' PROC02 COMMIT 3');
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
DBMS_OUTPUT.PUT_LINE(' PROC02 ERROR MESSAGE : ' || SQLERRM);
RAISE_APPLICATION_ERROR(-20000, ' PROC02 ERROR MESSAGE : ' || SQLERRM);
END;
/
EXEC PROC01(1); -- 정상입력
EXEC PROC01(0); -- 오류발생하여 모두 ROLLBACK 됨
오라클의 프로시져(Procedure) 트랜젝션 특성1 : https://blog.daonelab.com/post/24/135/