오늘 아침에 출근과 동시에 나를 반겨준 것은 다름아닌 오라60 오류! 반갑다 친구야
오늘은 오라60오류에 대해 살펴보자.
오라클 오류 ORA-00060은 "deadlock detected while waiting for resource", 즉 교착 상태(Deadlock) 가 발생했을 때 나타나는 오류입니다.
원인은 두 개 이상의 세션이 서로가 가진 자원을 기다리는 상황이 되어, 더 이상 진행할 수 없게 되었을 때 발생합니다.
예)
세션 A가 행 1을 잠금(Lock) → 세션 B가 행 2를 잠금
이후 세션 A가 행 2를 요청하고, 세션 B는 행 1을 요청하면
→ 서로 자원을 기다리면서 무한 대기 상태가 발생
오라클은 이 상황을 감지하면, 둘 중 하나의 트랜잭션을 강제로 종료시키고 ORA-00060 오류를 발생시킵니다.
해결 방법은
1. 트랜잭션 순서 통일
여러 세션에서 동일한 순서로 자원(테이블/행)을 액세스하도록 합니다.
2. 짧은 트랜잭션 유지
트랜잭션을 짧고 빠르게 처리하면 교착 상태 발생 가능성이 줄어듭니다.
3. 명시적 Lock 최소화
SELECT ... FOR UPDATE 같은 명시적 락 사용 시 신중하게 접근합니다.
4. Deadlock 트레이스 확인
alert.log 또는 trace 파일을 통해 어떤 세션/쿼리에서 문제가 발생했는지 확인할 수 있습니다.
일반적으로 trace 파일은 $ORACLE_HOME/diag/... 경로에 생성됩니다.
현재 락 세션 확인 할수도 있겠지만 접근권한이나 이미 상황이 종료된 경우도 있다.
--현재 락 상태 보기
SELECT
l.session_id,
l.locked_mode,
o.object_name,
o.object_type
FROM
v$locked_object l,
dba_objects o
WHERE
l.object_id = o.object_id;
다른 트랜젝션에서 동시에 테이블 업데이트 되는게 원인이였고 어떻게 해결할지는 아직 고민이다. 🤔
1. 트랜잭션 간 락 순서 통일 (락 순서 전략)
트랜잭션 A: UPDATE table1 → UPDATE table2
트랜잭션 B: UPDATE table2 → UPDATE table1
모든 트랜잭션이 동일한 순서로 테이블을 업데이트하도록 강제
-- 모두 table1 먼저, 그다음 table2
BEGIN
UPDATE table1 SET ... WHERE ...;
UPDATE table2 SET ... WHERE ...;
COMMIT;
END;
2. SELECT FOR UPDATE 사용 시 NOWAIT 또는 SKIP LOCKED 추가
A 세션: SELECT FOR UPDATE로 잠금
B 세션: 동일한 행을 SELECT FOR UPDATE 하려고 대기 → 교착 상태 발생 가능
-- NOWAIT: 잠금 못 잡으면 즉시 에러 반환
SELECT * FROM employees WHERE id = 101 FOR UPDATE NOWAIT;
-- SKIP LOCKED: 잠긴 행은 건너뜀
SELECT * FROM employees WHERE status = 'READY' FOR UPDATE SKIP LOCKED;
3. 인덱스 최적화로 풀스캔 방지
UPDATE 문에서 WHERE 절에 인덱스가 없어 다수 행에 락 발생
WHERE 절에 맞는 인덱스를 생성하여 대상 행만 빠르게 잠금
CREATE INDEX idx_orders_status ON orders(status);
4. 커밋을 빠르게 하여 락 지속 시간 단축
사용자 입력 후 커밋하지 않고 대기 → 긴 락 보유
트랜잭션은 빠르게 처리하고 즉시 커밋/롤백
BEGIN
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
COMMIT; -- 락 오래 잡지 않도록 즉시 커밋
END;
5. 애플리케이션에서 재시도 로직 구현
드물게 교착 상태가 발생하지만 비즈니스에 큰 문제는 아님
int attempts = 3;
while (attempts-- > 0) {
try {
// 데이터베이스 트랜잭션 로직
break; // 성공 시 탈출
} catch (SQLException e) {
if (e.getErrorCode() == 60) { // ORA-00060
Thread.sleep(1000); // 대기 후 재시도
} else {
throw e;
}
}
}
* Oracle 트레이스로 원인 분석
설정 방법
ALTER SESSION SET EVENTS '60 trace name errorstack level 3';
*오류 발생 시 trace 파일을 통해 어떤 세션이 어떤 자원을 점유하다 충돌이 발생했는지 확인 가능
*DB 서버의 user_dump_dest 경로에 trace 파일 생성됨
'에러' 카테고리의 다른 글
[KernelBase.dll] 프로그램이 실행이 안될 때 (0) | 2017.12.18 |
---|---|
[Mysql] Packet for query is too large (0) | 2017.11.15 |
[Mysql] Table 'mysql.plugin' doesn't exist (0) | 2017.06.23 |
[Visual stdio 2013] C4996 에러 (0) | 2016.12.02 |
[Windows] 컴퓨터에 MSVCP120D.dll이 없어 프로그램을 시작할 수 없습니다 (0) | 2016.12.02 |