2026년 10월 23일 | DBMS Error 가이드
이 글에서 다루는 내용
ORA-00054 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
ORA-00054 resource busy and acquire with NOWAIT specified 는?
ORA-00054 에러는 Oracle 데이터베이스에서 특정 리소스(테이블, 행 등)에 대한 잠금(Lock)을 획득하려 할 때, 해당 리소스가 이미 다른 세션에 의해 점유된 상태에서 NOWAIT 옵션을 사용했을 경우 즉시 발생하는 에러입니다. 즉, 잠금을 기다리지 않고 바로 실패를 반환하도록 명시했기 때문에, 리소스가 해제될 때까지 대기하지 않고 곧바로 에러를 던집니다. DDL 작업(예: ALTER TABLE, DROP TABLE, TRUNCATE) 수행 시 다른 세션이 해당 테이블을 사용 중일 때 가장 빈번하게 발생하며, 실무에서 매우 흔하게 마주치는 에러 중 하나입니다.
주요 발생 원인
- DDL 작업 시 다른 세션의 DML 트랜잭션이 완료되지 않은 경우
가장 대표적인 발생 원인입니다. Oracle에서 ALTER TABLE, DROP TABLE, TRUNCATE TABLE 등의 DDL 명령어를 실행하면, Oracle은 내부적으로 해당 테이블에 대한 배타적 잠금(Exclusive Lock)을 획득하려 시도합니다. 그런데 다른 세션에서 해당 테이블에 대한 INSERT, UPDATE, DELETE 등의 DML 작업이 커밋 또는 롤백 없이 진행 중이라면, DDL은 잠금을 획득할 수 없어 ORA-00054가 발생합니다. 특히 배치 작업이나 대량 데이터 처리 중에 DDL을 동시에 수행하려 할 때 자주 나타납니다.
SELECT ... FOR UPDATE NOWAIT사용 시 행 잠금 충돌
애플리케이션 개발 시 낙관적/비관적 잠금 전략을 구현하기 위해 SELECT ... FOR UPDATE NOWAIT 구문을 사용하는 경우가 많습니다. 이 구문은 선택한 행에 대한 잠금을 즉시 획득하지 못하면 기다리지 않고 바로 ORA-00054를 발생시킵니다. 특히 동시 사용자가 많은 OLTP 환경에서 동일한 행을 여러 세션이 동시에 수정하려 할 때 빈번하게 발생하므로, 에러 핸들링 로직이 반드시 필요합니다.
LOCK TABLE ... IN EXCLUSIVE MODE NOWAIT명령어 충돌
테이블 전체에 대한 배타적 잠금을 명시적으로 요청할 때도 ORA-00054가 발생할 수 있습니다. 다른 세션이 해당 테이블에 대한 어떠한 잠금(공유 잠금 포함)이라도 보유하고 있다면, NOWAIT 옵션으로 인해 즉시 에러가 반환됩니다. 이는 주로 마이그레이션 스크립트, 배치 프로그램, 또는 수동 유지보수 작업 중 실수로 다른 세션이 열려 있을 때 발생합니다.
해결 방법
방법 1: 잠금을 보유한 세션 확인 및 종료
먼저 어떤 세션이 잠금을 보유하고 있는지 확인합니다.
-- 현재 잠금 보유 세션 확인
SELECT
s.sid,
s.serial#,
s.username,
s.status,
s.machine,
s.program,
l.type,
l.lmode,
l.request,
o.object_name,
o.object_type
FROM
v$session s
JOIN v$lock l ON s.sid = l.sid
LEFT JOIN dba_objects o ON l.id1 = o.object_id
WHERE
l.block = 1 -- 다른 세션을 블로킹 중인 세션만 조회
ORDER BY
s.sid;
블로킹 세션을 확인한 후, 해당 세션을 종료합니다.
-- 블로킹 세션 강제 종료 (DBA 권한 필요)
ALTER SYSTEM KILL SESSION 'sid,serial#' IMMEDIATE;
-- 예시
ALTER SYSTEM KILL SESSION '142,3891' IMMEDIATE;
방법 2: WAIT 옵션으로 변경하여 일정 시간 대기
NOWAIT 대신 WAIT n 옵션을 사용하면, 지정한 초(秒) 동안 잠금을 기다린 후 실패합니다.
-- NOWAIT 대신 WAIT 사용 (5초 대기)
SELECT *
FROM employees
FOR UPDATE WAIT 5;
-- 테이블 잠금 시 WAIT 옵션 사용
LOCK TABLE orders IN EXCLUSIVE MODE WAIT 10;
방법 3: DDL 전 활성 트랜잭션 확인 및 정리
DDL 수행 전에 해당 테이블과 관련된 활성 트랜잭션이 있는지 반드시 사전 점검합니다.
-- 특정 테이블에 대한 잠금 현황 확인
SELECT
s.sid,
s.serial#,
s.username,
s.sql_id,
s.status,
o.object_name,
DECODE(l.lmode,
0, 'None',
1, 'Null',
2, 'Row Share',
3, 'Row Exclusive',
4, 'Share',
5, 'Share Row Exclusive',
6, 'Exclusive') AS lock_mode
FROM
v$session s
JOIN v$lock l ON s.sid = l.sid
JOIN dba_objects o ON l.id1 = o.object_id
WHERE
o.object_name = 'EMPLOYEES' -- 대상 테이블명
AND o.object_type = 'TABLE';
-- 활성 트랜잭션이 있다면 애플리케이션 측에서 커밋/롤백 유도 후 DDL 수행
-- DDL 예시
ALTER TABLE employees ADD (dept_code VARCHAR2(10));
방법 4: SELECT FOR UPDATE NOWAIT 에러 핸들링
애플리케이션 코드에서 ORA-00054 발생 시 재시도 로직을 구현합니다.
-- PL/SQL에서 ORA-00054 예외 처리 예제
DECLARE
resource_busy EXCEPTION;
PRAGMA EXCEPTION_INIT(resource_busy, -54);
v_retry NUMBER := 0;
v_max_retry NUMBER := 3;
BEGIN
LOOP
BEGIN
SELECT employee_id, salary
INTO ...
FROM employees
WHERE employee_id = 100
FOR UPDATE NOWAIT;
-- 잠금 성공 시 처리 로직
UPDATE employees
SET salary = salary * 1.1
WHERE employee_id = 100;
COMMIT;
EXIT; -- 성공 시 루프 종료
EXCEPTION
WHEN resource_busy THEN
v_retry := v_retry + 1;
IF v_retry >= v_max_retry THEN
RAISE_APPLICATION_ERROR(-20001,
'리소스가 사용 중입니다. 잠시 후 다시 시도하세요. (재시도 횟수 초과)');
END IF;
-- 잠시 대기 후 재시도
DBMS_LOCK.SLEEP(2);
END;
END LOOP;
END;
/
예방 방법
- DDL 수행 전 유지보수 창(Maintenance Window) 확보 및 세션 점검 절차 수립
운영 환경에서 DDL을 수행하기 전에는 반드시 사전에 활성 세션과 잠금 현황을 점검하는 절차를 표준화해야 합니다. 가능하다면 서비스 중단 시간(Maintenance Window)을 공식적으로 확보하고, 해당 시간에 애플리케이션 연결을 차단한 뒤 DDL을 수행하는 것이 가장 안전합니다. 또한 DDL_LOCK_TIMEOUT 파라미터(Oracle 11g 이상)를 설정하면 DDL이 지정된 시간 동안 잠금을 기다리게 할 수 있어, 단순 NOWAIT 방식보다 유연하게 운영할 수 있습니다.
“`sql
— DDL이 잠금 획득을 최대 30초 동안 대기하도록 설정
ALTER SESSION SET DDL_LOCK_TIMEOUT = 30;
— 이후 DDL 수행
ALTER TABLE employees ADD (bonus NUMBER(10,2));
“`
- 트랜잭션을 짧고 명확하게 유지하고, 장기 트랜잭션 모니터링 체계 구축
장기 실행 트랜잭션(Long Running Transaction)은 잠금 충돌의 가장 근본적인 원인입니다. 개발 단계에서부터 트랜잭션을 가능한 한 짧고 명확하게 설계하고, 커밋을 적시에 수행하도록 코드 리뷰 기준을 마련해야 합니다. 운영 환경에서는 아래 쿼리를 활용하여 장기 트랜잭션을 정기적으로 모니터링하고, 임계치를 초과하는 경우 담당자에게 알림이 가도록 자동화된 모니터링 체계를 구축하는 것을 권장합니다.
“`sql
— 10분 이상 실행 중인 활성 트랜잭션 모니터링
SELECT
s.sid,
s.serial#,
s.username,
s.machine,
t.start_time,
ROUND((SYSDATE – TO_DATE(t.start_time, ‘MM/DD/YY HH24:MI:SS’)) 24 60, 2)
AS elapsed_minutes,
s.sql_id
FROM
v$session s
JOIN v$transaction t ON s.taddr = t.addr
WHERE
ROUND((SYSDATE – TO_DATE(t.start_time, ‘MM/DD/YY HH24:MI:SS’)) 24 60, 2) > 10
ORDER BY
elapsed_minutes DESC;
“`
관련 에러
- ORA-00055:
too many enqueue resources— 시스템 내 잠금 리소스가 너무 많이 사용되고 있을 때 발생하며,ENQUEUE_RESOURCES파라미터 조정이 필요합니다. - ORA-00060:
deadlock detected while waiting for resource— 두 개 이상의 세션이 서로 상대방의 잠금을 기다리는 교착상태(Deadlock) 발생 시 나타나며, ORA-00054와 함께 잠금 관련 에러로 자주 언급됩니다. - ORA-04021:
timeout occurred while waiting to lock object— 패키지나 프로시저 등 PL/SQL 객체에 대한 잠금 타임아웃 시 발생합니다. - ORA-01013:
user requested cancel of current operation— 클라이언트 측에서 대기 중 작업을 취소했을 때 발생하며, NOWAIT 에러와 유사한 맥락에서 다루어집니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.