Python을 배워보자
오라클 저장 프로시저 내부 오류 캡처 및 Python oracledb로 애플리케이션 레벨 오류 처리 방법
_Blue_Sky_
2025. 6. 15. 21:08
728x90

오라클 데이터베이스의 저장 프로시저(Stored Procedure, SP)에서 발생하는 내부 오류를 상세히 파악하고, Python의 oracledb 모듈을 사용해 애플리케이션 레벨에서 이를 효과적으로 캡처하는 방법을 설명합니다. 이 글은 오라클 PL/SQL과 Python 개발자를 위해 실용적인 예제와 함께 오류 처리 기법을 다룹니다.
1. 오라클 저장 프로시저에서 내부 오류 캡처
오라클 저장 프로시저에서 오류를 캡처하려면 PL/SQL의 **예외 처리 블록(EXCEPTION)**을 사용합니다. 이를 통해 오류 코드(SQLCODE)와 오류 메시지(SQLERRM)를 기록하거나 호출한 애플리케이션으로 전달할 수 있습니다.
예제: 오류 로깅 테이블에 기록
CREATE TABLE ERROR_LOG (
ERROR_CODE VARCHAR2(20),
ERROR_DESC VARCHAR2(400),
ERROR_DATE TIMESTAMP DEFAULT SYSTIMESTAMP
);
CREATE OR REPLACE PROCEDURE MY_PROC AS
V_SQLCODE VARCHAR2(20);
V_SQLERRM VARCHAR2(400);
BEGIN
-- 예외를 유발하는 코드 (예: 0으로 나누기)
DECLARE
V_NUM NUMBER := 1 / 0;
BEGIN
NULL;
END;
EXCEPTION
WHEN OTHERS THEN
V_SQLCODE := SQLCODE;
V_SQLERRM := SQLERRM;
-- 오류 로깅 테이블에 삽입
INSERT INTO ERROR_LOG (ERROR_CODE, ERROR_DESC)
VALUES (V_SQLCODE, V_SQLERRM);
COMMIT;
-- 호출자에게 오류 전파
RAISE_APPLICATION_ERROR(-20001, 'Error: ' || V_SQLERRM);
END;
/
-
설명:
-
SQLCODE: 오류 코드 (예: ORA-01476은 0으로 나누기 오류).
-
SQLERRM: 오류 메시지 (최대 512바이트).
-
RAISE_APPLICATION_ERROR: 사용자 정의 오류를 호출자에게 전달.
-
오류를 ERROR_LOG 테이블에 저장해 추후 분석 가능.
-
팁:
-
WHEN OTHERS는 모든 예외를 포괄하지만, 특정 예외(예: NO_DATA_FOUND, ZERO_DIVIDE)를 명시적으로 처리하는 것이 좋습니다.
-
DBMS_UTILITY.FORMAT_ERROR_STACK 또는 DBMS_UTILITY.FORMAT_ERROR_BACKTRACE를 사용하면 더 자세한 오류 스택 정보를 얻을 수 있습니다.
728x90
2. Python oracledb로 오류 캡처
Python의 oracledb 모듈은 오라클 데이터베이스와 상호작용하며, 저장 프로시저 호출 시 발생하는 오류를 체계적으로 처리할 수 있습니다. 모든 oracledb 예외는 oracledb.Error에서 상속되며, 오류 객체에서 상세 정보를 추출할 수 있습니다.
예제: 저장 프로시저 호출 및 오류 처리
import oracledb
import logging
# 로깅 설정
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
def call_stored_procedure():
try:
# 데이터베이스 연결
connection = oracledb.connect(user="your_user", password="your_password", dsn="localhost:1521/orclpdb")
cursor = connection.cursor()
# 저장 프로시저 호출
cursor.callproc("MY_PROC")
# 커밋 (필요한 경우)
connection.commit()
logging.info("Stored procedure executed successfully.")
except oracledb.DatabaseError as e:
error_obj, = e.args
logging.error(f"Database error occurred: Code={error_obj.code}, Message={error_obj.message}")
# 추가 정보 출력
print(f"Full Code: {error_obj.full_code}")
print(f"Context: {error_obj.context}")
except oracledb.Error as e:
error_obj, = e.args
logging.error(f"oracledb error occurred: {error_obj.message}")
except Exception as e:
logging.critical(f"Unexpected error: {e}")
finally:
# 자원 정리
if 'cursor' in locals():
cursor.close()
if 'connection' in locals():
connection.close()
logging.info("Database resources closed.")
if __name__ == "__main__":
call_stored_procedure()
-
설명:
-
oracledb.connect: 데이터베이스 연결 설정.
-
cursor.callproc: 저장 프로시저 호출.
-
oracledb.DatabaseError: 데이터베이스 관련 오류 (예: ORA-20001).
-
error_obj: 오류 객체로, code, message, full_code, context 속성을 제공.
-
logging: 오류를 로그 파일에 기록해 디버깅 용이.
-
finally: 연결 및 커서 자원 정리.
-
오류 객체 속성:
-
code: 오류 코드 (예: -20001).
-
message: 오류 메시지.
-
full_code: 전체 오류 코드 (예: ORA-20001).
-
context: 오류가 발생한 컨텍스트 정보.
Thin vs Thick 모드:
-
oracledb는 Thin(기본)과 Thick 모드를 지원합니다. Thin 모드는 Python 자체 네트워킹을 사용하며, Thick 모드는 Oracle 클라이언트 라이브러리를 사용합니다.
-
Thin 모드에서는 DPY-XXXX 접두사의 오류가 발생할 수 있으며, Thick 모드에서는 ORA-XXXX 또는 DPI-XXXX 오류가 발생할 수 있습니다.
3. 고급 오류 처리 기법
-
오류 스택 추적:
-
PL/SQL에서 DBMS_UTILITY.FORMAT_ERROR_BACKTRACE를 사용해 오류 발생 위치를 추적.
EXCEPTION WHEN OTHERS THEN INSERT INTO ERROR_LOG (ERROR_CODE, ERROR_DESC) VALUES (SQLCODE, SQLERRM || ' Backtrace: ' || DBMS_UTILITY.FORMAT_ERROR_BACKTRACE); COMMIT; RAISE;
-
-
사용자 정의 예외:
-
Python에서 특정 오류 코드를 기반으로 커스텀 처리 로직 추가.
if error_obj.code == -20001: logging.warning("Custom application error detected. Retrying...") # 재시도 로직
-
-
비동기 처리:
-
oracledb의 비동기 메서드(AsyncCursor.execute, AsyncConnection)를 사용해 대규모 작업에서 오류 처리 최적화.
-
-
연결 풀링:
-
다중 사용자 환경에서는 oracledb.create_pool을 사용해 연결 풀을 생성, 오류 발생 시 풀에서 새 연결을 획득하도록 설계.
-
4. 디버깅 팁
-
오라클 클라이언트 로그 활성화:
-
Thick 모드에서 OCI 추적 활성화:
export EVENT_10842=15
$HOME/instantclient/log/diag/clients 디렉토리에 로그 생성.
-
-
DPI 디버깅:
-
oracledb Thin 모드에서 DPI 디버깅 활성화:
oracledb.defaults.debug_dpi = True
-
-
SQL*Plus로 테스트:
-
저장 프로시저를 SQL*Plus에서 실행해 예상 오류 확인:
EXEC MY_PROC; SELECT * FROM ERROR_LOG;
-
5. 결론
오라클 저장 프로시저에서 내부 오류를 캡처하려면 PL/SQL 예외 처리와 로깅 테이블을 활용하고, RAISE_APPLICATION_ERROR로 애플리케이션에 오류를 전달합니다. Python oracledb에서는 try-except 블록과 oracledb.Error를 사용해 오류를 체계적으로 처리하며, 로깅과 자원 정리를 철저히 수행해야 합니다. 추가로 오류 스택 추적, 사용자 정의 예외, 연결 풀링 등을 활용하면 더 robust한 애플리케이션을 구축할 수 있습니다.
728x90