Oracle 19c에서 ORA-00060이 발생했다면, 먼저 trace 파일의 데드락 그래프를 보며 서로 기다린 트랜잭션과 자원을 연결해야 합니다. 단순히 오류가 난 SQL만 재실행하면 잠깐 지나갈 수는 있어도, 두 업무 흐름이 반대 순서로 행을 잡는 구조는 그대로 남습니다.
Oracle은 데드락을 감지하면 관련 문장 하나를 롤백하고 ORA-00060을 반환합니다. 이미 같은 트랜잭션에서 성공한 앞선 변경까지 자동으로 취소되는 것은 아니므로, 애플리케이션은 재시도 전에 트랜잭션 경계와 중복 처리 방식을 확인해야 합니다.
핵심 답변
적용 대상은 Oracle Database 19c에서 ORA-00060이 기록된 DML 또는 잠금 충돌입니다. trace의 ‘Deadlock graph’와 오류 직후 SQL을 보관한 뒤, 두 세션이 같은 자원을 같은 순서로 접근하도록 수정합니다. 오류를 무제한 재시도하거나 세션을 먼저 종료하는 방식은 원인 확인 전에는 쓰지 않습니다.
ORA-00060에서 먼저 확인할 범위
| 항목 | 적용/확인 내용 | 운영 영향 또는 예외 |
|---|---|---|
| 오류의 의미 | 둘 이상 트랜잭션이 서로 가진 자원을 기다리는 순환 대기입니다. | 일반적인 단방향 블로킹과 달리 기다려도 스스로 풀리지 않습니다. |
| 자동 처리 범위 | Oracle이 데드락에 걸린 문장 하나를 롤백해 한쪽 대기를 끊습니다. | 앞서 성공한 DML은 현재 트랜잭션에 남을 수 있습니다. |
| 우선 증적 | ORA-00060 trace, 오류 시각, 모듈·클라이언트 식별자, 애플리케이션 SQL입니다. | 재현 전 로그가 덮이면 원인 SQL의 순서를 잃기 쉽습니다. |
데드락은 ‘행 두 개’보다 ‘접근 순서’ 문제에 가깝다
가령 주문 처리 A가 주문 행을 갱신한 뒤 재고 행을 갱신하고, 처리 B가 재고 행을 먼저 갱신한 뒤 같은 주문 행을 갱신한다고 가정해 보겠습니다. 두 작업이 겹치면 A는 B의 재고 행을, B는 A의 주문 행을 기다리게 됩니다. Oracle은 그 고리를 발견하면 한 문장에 ORA-00060을 돌려줍니다.
테스트 환경의 최소 재현 구조
CREATE TABLE order_header (
order_id NUMBER PRIMARY KEY,
status VARCHAR2(20) NOT NULL
);
CREATE TABLE inventory_item (
item_id NUMBER PRIMARY KEY,
qty NUMBER NOT NULL
);
INSERT INTO order_header (order_id, status) VALUES (1001, 'READY');
INSERT INTO inventory_item (item_id, qty) VALUES (501, 10);
COMMIT;
실행 목적
목적: 서로 다른 두 행을 같은 테스트 데이터로 준비합니다. 권한: 자신의 스키마에 테이블을 만들고 DML할 권한이 필요합니다. 적용 버전: Oracle Database 19c. 예상 결과: 두 행이 각각 한 건씩 생성됩니다.
아래 SQL은 서로 다른 세션에서 순서를 반대로 실행할 때만 데드락을 관찰하기 위한 예제입니다. 한 세션에서 모두 실행하면 데드락이 생기지 않습니다.
-- 세션 A: 먼저 실행하고 COMMIT하지 않는다.
UPDATE order_header
SET status = 'PROCESSING'
WHERE order_id = 1001;
-- 세션 B: 먼저 실행하고 COMMIT하지 않는다.
UPDATE inventory_item
SET qty = qty - 1
WHERE item_id = 501;
-- 세션 A: 다음에 실행하면 세션 B가 가진 행을 기다린다.
UPDATE inventory_item
SET qty = qty - 1
WHERE item_id = 501;
-- 세션 B: 다음에 실행하면 순환 대기가 완성될 수 있다.
UPDATE order_header
SET status = 'PROCESSING'
WHERE order_id = 1001;
운영 환경 주의
운영에서 이 순서를 의도적으로 재현하지 않습니다. ORA-00060이 난 세션이 어느 문장에서 멈췄는지와 별개로, 같은 트랜잭션의 앞선 변경은 남아 있을 수 있습니다. 오류 처리에서 전체 작업을 다시 시작한다면 멱등 키·중복 INSERT·외부 호출의 보상 여부를 함께 설계해야 합니다.
실행 목적
목적: 순환 대기가 만들어지는 접근 순서를 이해합니다. 권한: 각 세션에 대상 테이블 UPDATE 권한이 필요합니다. 예상 결과: 한 세션의 마지막 UPDATE가 ORA-00060을 받을 수 있으며, 실제 희생 세션은 고정되지 않습니다.
trace 파일을 읽는 순서
Oracle 오류 도움말은 ORA-00060이 나면 trace 파일에서 참여 트랜잭션과 자원을 확인하라고 안내합니다. alert log에서 발생 시각을 좁힌 뒤 해당 시각의 trace 파일을 열고, 아래 순서로 업무 맥락을 복원합니다.
- Deadlock graph에서 대기 방향이 닫힌 고리인지 확인합니다. 자원 종류와 대기·보유 관계를 먼저 읽고, SQL 텍스트만 보고 결론 내리지 않습니다.
- 그래프의 세션·트랜잭션 정보를 오류 시각의 애플리케이션 로그와 연결합니다. 가능하면 MODULE, ACTION, CLIENT_IDENTIFIER를 함께 남겨 배치와 화면 요청을 구분합니다.
- trace에 이어 나오는 오류 시점 SQL과 바인드 값 취급 방침을 확인합니다. 민감한 값은 복사하거나 공개 로그에 남기지 않습니다.
- 두 코드 경로가 같은 테이블·행 집합을 어떤 순서로 갱신했는지 비교합니다. 공통 정렬 키를 정해 항상 같은 순서로 잠그는 수정이 우선입니다.
오류 시각의 세션 맥락을 보조로 조회하기
SELECT s.sid,
s.serial#,
s.username,
s.module,
s.action,
s.client_identifier,
s.status,
s.sql_id
FROM v$session s
WHERE s.username = :schema_name
ORDER BY s.logon_time DESC;
실행 목적
목적: trace의 시각·세션 단서를 애플리케이션 업무 단위와 연결합니다. 권한: 일반적으로 V_$SESSION 조회 권한 또는 동등한 진단 권한이 필요합니다. 적용 버전: Oracle Database 19c. 예상 결과: 현재 또는 최근 접속 세션의 식별 정보가 반환됩니다. 과거에 종료된 세션은 이 조회만으로 복원되지 않습니다.
수정 전후에 확인할 것
| 단계 | 확인 | 중단 또는 다음 행동 |
|---|---|---|
| 수정 전 | trace의 자원 고리와 두 호출 경로의 갱신 순서가 일치하는지 확인합니다. | 일치하지 않으면 추정 수정 대신 다음 발생의 식별 로그를 보강합니다. |
| 배포 | 공통 키 기준 정렬, 짧은 트랜잭션, 재시도 횟수·간격을 코드 리뷰합니다. | 외부 결제·메시지 발행이 섞이면 멱등성 검토 없이 자동 재시도하지 않습니다. |
| 배포 후 | ORA-00060 건수, 처리 지연, 중복 업무 기록을 같은 기간 기준으로 비교합니다. | 재발하면 새 trace로 같은 고리인지 먼저 분류합니다. |
재발을 줄이는 설계 원칙
가장 직접적인 해결책은 모든 코드 경로가 같은 순서로 행을 갱신하도록 정하는 것입니다. 예를 들어 주문과 재고를 함께 잠가야 하면 항상 주문 ID, 재고 ID 순으로 처리하고, 한 트랜잭션이 잡는 행 수와 외부 호출 시간을 줄입니다. 인덱스를 추가하거나 세션을 종료하는 조치는 증상과 원인에 따라 달라지므로, trace가 가리킨 자원과 실행 경로가 확인되기 전에는 만능 처방으로 쓰지 않습니다.
롤백 방법
테스트 재현을 마치면 두 세션 모두 ROLLBACK으로 종료해 잠금과 변경을 정리합니다. 운영 애플리케이션은 ORA-00060 뒤에도 현재 트랜잭션의 앞선 변경이 남는지 확인한 뒤, 명시적으로 ROLLBACK하거나 저장점으로 되돌리는 경계를 코드에 둡니다.
흔한 오해
- “데드락이면 트랜잭션 전체가 사라진다”: Oracle의 자동 해소는 데드락에 관련된 문장 하나의 롤백입니다. 애플리케이션의 전체 작업 단위는 별도로 정리합니다.
- “에러가 난 SQL만 무조건 재시도하면 된다”: 순환 접근이 남으면 재발합니다. 재시도는 짧고 멱등한 작업에서만 제한적으로 사용합니다.
- “블로킹 세션을 종료하면 원인이 해결된다”: 데드락은 이미 Oracle이 순환을 끊은 뒤일 수 있습니다. 종료보다 trace 보존과 접근 순서 수정이 먼저입니다.
마무리
ORA-00060 대응의 출발점은 trace에서 실제 대기 고리를 읽는 일입니다. 그다음 두 업무 흐름을 같은 잠금 순서로 맞추고, 오류 뒤 남을 수 있는 트랜잭션 상태와 재시도 중복을 분리해 다루면 일회성 해소가 재발 방지로 이어집니다.