Oracle ORA-02067 오류 원인과 해결 방법 완벽 가이드

ORA-02067
2026년 08월 09일 | DBMS Error 가이드

이 글에서 다루는 내용

ORA-02067 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.

ORA-02067 transaction or savepoint rollback required 는?

ORA-02067은 분산 트랜잭션(Distributed Transaction) 환경에서 원격 데이터베이스와의 작업 중 오류가 발생했을 때, 현재 트랜잭션 또는 특정 세이브포인트까지 롤백이 반드시 필요한 상태임을 알려주는 에러입니다. 이 에러는 주로 데이터베이스 링크(Database Link)를 통한 원격 프로시저 호출(RPC) 또는 분산 SQL 실행 중에 발생하며, Oracle이 트랜잭션의 일관성을 유지하기 위해 강제로 롤백을 요구하는 상황입니다. 즉, 현재 트랜잭션 상태가 커밋(COMMIT)이 불가능한 상태이므로, 반드시 ROLLBACK 명령을 수행해야만 이후 작업을 정상적으로 진행할 수 있습니다.


주요 발생 원인

1. 분산 트랜잭션 중 원격 데이터베이스 오류 발생

데이터베이스 링크를 통해 원격 DB에 DML 작업을 수행하던 중 네트워크 단절, 원격 서버 다운, 타임아웃 등의 오류가 발생하면 Oracle은 해당 트랜잭션을 더 이상 신뢰할 수 없는 상태(in-doubt transaction)로 판단합니다. 이 경우 Oracle은 트랜잭션의 원자성(Atomicity)을 보장하기 위해 현재 트랜잭션 전체 또는 세이브포인트까지의 롤백을 강제로 요구하며 ORA-02067을 발생시킵니다.

2. 원격 프로시저 또는 트리거 내부에서의 예외 미처리

데이터베이스 링크를 통해 호출되는 원격 저장 프로시저(Remote Stored Procedure)나 원격 트리거 내부에서 예외가 발생했을 때, 해당 예외가 적절히 처리되지 않고 상위로 전파되는 경우 이 에러가 발생합니다. 특히 원격지에서 발생한 예외는 로컬 트랜잭션의 일부로 묶여 있기 때문에, 예외 처리 없이 트랜잭션을 계속 진행하면 Oracle은 일관성 보장을 위해 롤백을 강제합니다.

3. 2PC(Two-Phase Commit) 프로토콜 실패

Oracle의 분산 트랜잭션은 2단계 커밋(Two-Phase Commit, 2PC) 프로토콜을 사용합니다. 1단계(Prepare Phase)에서 원격 노드 중 하나라도 준비 완료 신호를 보내지 못하거나 응답하지 않으면, 코디네이터(Coordinator) 역할을 하는 로컬 DB는 전체 트랜잭션을 롤백해야 합니다. 이 과정에서 ORA-02067이 발생하며, DBA_2PC_PENDING 뷰를 통해 미완료 분산 트랜잭션을 확인할 수 있습니다.


해결 방법

원인 1 해결: 분산 트랜잭션 롤백 후 재시도

ORA-02067이 발생하면 가장 먼저 현재 트랜잭션을 롤백해야 합니다. 이후 문제가 된 원격 연결 상태를 확인하고 재시도합니다.

-- 1. 즉시 롤백 수행
ROLLBACK;

-- 2. 데이터베이스 링크 연결 상태 확인
SELECT * FROM V$DBLINK;

-- 3. 문제가 된 DB 링크를 닫고 재연결
ALTER SESSION CLOSE DATABASE LINK remote_db_link;

-- 4. 이후 작업 재시도
BEGIN
    INSERT INTO remote_table@remote_db_link (col1, col2)
    VALUES ('value1', 'value2');
    COMMIT;
EXCEPTION
    WHEN OTHERS THEN
        ROLLBACK;
        DBMS_OUTPUT.PUT_LINE('Error: ' || SQLERRM);
END;
/

원인 2 해결: 원격 프로시저 호출 시 예외 처리 강화

원격 프로시저 호출 시 반드시 예외 처리 블록을 추가하고, 오류 발생 시 명시적으로 롤백합니다.

-- 잘못된 예 (예외 처리 없음)
BEGIN
    remote_procedure@remote_db_link(p_id => 100);
    COMMIT;
END;
/

-- 올바른 예 (예외 처리 포함)
DECLARE
    v_savepoint_name VARCHAR2(30) := 'SP_REMOTE_CALL';
BEGIN
    -- 세이브포인트 설정
    SAVEPOINT SP_REMOTE_CALL;
    
    -- 로컬 작업
    UPDATE local_table SET status = 'PROCESSING' WHERE id = 100;
    
    -- 원격 프로시저 호출
    remote_procedure@remote_db_link(p_id => 100);
    
    -- 원격 테이블 업데이트
    UPDATE remote_table@remote_db_link 
    SET status = 'DONE', updated_date = SYSDATE 
    WHERE id = 100;
    
    COMMIT;
    DBMS_OUTPUT.PUT_LINE('Transaction completed successfully.');
    
EXCEPTION
    WHEN ORA_02067 OR OTHERS THEN
        -- ORA-02067 발생 시 반드시 전체 롤백
        ROLLBACK;
        DBMS_OUTPUT.PUT_LINE('Distributed transaction failed. Rolled back. Error: ' || SQLERRM);
        -- 필요 시 에러 로깅
        INSERT INTO error_log (error_code, error_msg, created_date)
        VALUES (SQLCODE, SQLERRM, SYSDATE);
        COMMIT; -- 에러 로그만 커밋
END;
/

원인 3 해결: 미완료 분산 트랜잭션(In-Doubt Transaction) 처리

2PC 실패로 인한 미완료 트랜잭션은 DBA_2PC_PENDING 뷰를 통해 확인하고 수동으로 처리합니다.

-- 미완료 분산 트랜잭션 확인
SELECT LOCAL_TRAN_ID, 
       GLOBAL_TRAN_ID, 
       STATE, 
       MIXED, 
       ADVICE, 
       TRAN_COMMENT,
       FAIL_TIME,
       FORCE_TIME
FROM DBA_2PC_PENDING;

-- 미완료 트랜잭션 강제 커밋 (데이터 정합성 확인 후)
EXECUTE DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('local_tran_id_here');

-- 또는 강제 롤백
ROLLBACK FORCE 'local_tran_id_here';

-- 강제 커밋이 필요한 경우
COMMIT FORCE 'local_tran_id_here';

-- 처리 후 확인
SELECT * FROM DBA_2PC_PENDING;
SELECT * FROM DBA_2PC_NEIGHBORS;

> ⚠️ 주의: COMMIT FORCE 또는 ROLLBACK FORCE는 반드시 원격 데이터베이스 관리자와 협의 후 데이터 정합성을 확인한 다음 수행해야 합니다.


예방 방법

1. 분산 트랜잭션 최소화 및 명시적 예외 처리 표준화

분산 트랜잭션은 네트워크 장애, 원격 서버 장애 등 다양한 외부 요인에 취약하므로 설계 단계에서 분산 트랜잭션의 범위를 최소화하는 것이 중요합니다. 모든 데이터베이스 링크를 사용하는 PL/SQL 코드에는 반드시 EXCEPTION WHEN OTHERS THEN ROLLBACK 패턴을 표준으로 적용하고, 애플리케이션 레벨에서도 분산 트랜잭션 실패 시 재시도(Retry) 로직과 알림 체계를 구축해야 합니다.

-- 표준화된 분산 트랜잭션 템플릿
CREATE OR REPLACE PROCEDURE distributed_transaction_template AS
BEGIN
    -- 분산 작업 수행
    NULL; -- 실제 작업으로 대체
    COMMIT;
EXCEPTION
    WHEN OTHERS THEN
        ROLLBACK; -- ORA-02067 포함 모든 오류에 롤백
        -- 에러 로깅 및 알림
        RAISE;
END;
/

2. 분산 트랜잭션 모니터링 자동화

DBA_2PC_PENDING 뷰와 Oracle Alert Log를 정기적으로 모니터링하여 미완료 분산 트랜잭션을 조기에 감지하고 처리하는 자동화 스크립트를 운영해야 합니다. 또한 DISTRIBUTED_LOCK_TIMEOUT 파라미터를 적절히 설정하여 분산 트랜잭션 대기 시간을 제어하고, 정기적인 데이터베이스 링크 상태 점검 Job을 DBMS_SCHEDULER로 등록하여 운영하는 것을 권장합니다.

-- 미완료 분산 트랜잭션 자동 모니터링 Job 예시
BEGIN
    DBMS_SCHEDULER.CREATE_JOB(
        job_name        => 'MONITOR_2PC_PENDING',
        job_type        => 'PLSQL_BLOCK',
        job_action      => '
            DECLARE
                v_count NUMBER;
            BEGIN
                SELECT COUNT(*) INTO v_count FROM DBA_2PC_PENDING;
                IF v_count > 0 THEN
                    -- 알림 발송 로직 (이메일, 모니터링 시스템 등)
                    DBMS_OUTPUT.PUT_LINE(''In-doubt transactions found: '' || v_count);
                END IF;
            END;',
        start_date      => SYSTIMESTAMP,
        repeat_interval => 'FREQ=HOURLY;INTERVAL=1',
        enabled         => TRUE,
        comments        => 'Monitor in-doubt distributed transactions'
    );
END;
/

관련 에러

  • ORA-02050: transaction rolled back, some remote DBs may be in-doubt — 분산 트랜잭션 롤백 후 일부 원격 DB가 미확인 상태일 때 발생하며 ORA-02067과 함께 자주 나타납니다.
  • ORA-02055: distributed update operation failed; rollback required — 분산 업데이트 작업 실패 시 롤백이 필요함을 알리는 에러로, ORA-02067과 유사한 맥락에서 발생합니다.
  • ORA-02056: 2PC: number: bad two-phase command number from number — 2단계 커밋 프로토콜 처리 중 잘못된 명령 번호가 수신되었을 때 발생합니다.
  • ORA-02051: transaction was already in doubt — 이미 미완료 상태인 트랜잭션에 대해 작업을 시도할 때 발생합니다.
  • ORA-01591: lock held by in-doubt distributed transaction — 미완료 분산 트랜잭션이 보유한 락으로 인해 다른 트랜잭션이 블로킹되는 상황에서 발생합니다.

DBMS 에러 코드 시리즈

주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.

본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.

댓글 남기기