[Oracle] ORA-08177: can't serialize access for this transaction

728x90

어떤 때 ORA-08177이 나나?

  • 트랜잭션 A가 SET TRANSACTION ISOLATION LEVEL SERIALIZABLE 로 시작.
  • A가 본 "스냅샷 시점(트랜잭션 시작 SCN)" 이후에 B가 같은 행(또는 동등한 키 범위)을 커밋으로 변경.
  • 그 다음 A가 그 행(또는 범위)을 변경(UPDATE/DELETE/INSERT) 하려는 순간,
    A에서 ORA-08177: "can't serialize access for this transaction" 발생, A는 해당 문장을 실패(보통 전체 트랜잭션 롤백).
시간 트랜잭션 A 트랜잭션 B
T1 SELECT saldo FROM acct WHERE id=1; -- 100 -
T2 - UPDATE acct SET saldo=50 WHERE id=1;
T3 - COMMIT;
T4 UPDATE acct SET saldo=80 WHERE id=1; → ORA-08177 -

핵심: 에러는 보통 A(직렬화 트랜잭션) 쪽에서 납니다.
B는 대기하지 않고 정상 커밋되며, 기다리지도/에러도 나지 않습니다.

(물론 A가 SELECT … FOR UPDATE 등으로 먼저 락을 잡아두었다면 B는 그 락 때문에 대기/실패할 수 있음)

참고
SERIALIZABLE은 "순차 실행"이 아니라 논리적 직렬성을 보장하는 모드이고,
이때 충돌이 나면 대기시키지 않고 에러(ORA-08177) 로 실패시켜서 일관성을 지킵니다.

왜 "대기"가 아니라 "에러"일까?

SERIALIZABLE은 "A가 시작한 시점의 일관된 세상"을 가정합니다.

그 이후에 커밋된 변경이 A의 의도와 충돌하면 직렬화 가능한 순서를 만들 수 없기 때문에 대기해서 해결될 문제가 아니고,

즉시 실패시켜 재시도하도록 합니다.

(오라클의 직렬화는 MVCC 스냅샷 + 충돌 감지 방식)

방지/대응 전략

  1. 락으로 선점(비관적 제어)
    • A가 변경할 후보 행을 처음부터 잡아둡니다.
    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
    SELECT ... FROM acct WHERE id=1 FOR UPDATE;  -- 행락 선점
    -- 이후 UPDATE/DELETE 수행
    
    이렇게 하면 그 행에 대해 B가 UPDATE하려 할 때 대기(또는 NOWAIT 지정 시 즉시 실패)하게 됩니다.
    • 범위 삽입(phantom)까지 막아야 하면, 애플리케이션 락(DBMS_LOCK), 상위 테이블 락(짧게), 또는 업무 규칙상 "키 할당자"를 단일화하는 등 업무 단위 직렬화가 필요할 수 있습니다.
  2. 낮은 고립 수준으로 전환(READ COMMITTED)
    • 직렬화가 꼭 필요하지 않다면 READ COMMITTED(오라클 기본)로 돌려 ORA-08177 자체를 피함
    • 오라클은 SELECT에 대해 일관 읽기를 제공하므로, 다수 업무는 READ COMMITTED로 충분한 경우가 많음
  3. 낙관적 동시성 제어 + 재시도 표준화
    • 버전 컬럼(예: row_version/updated_at)을 두고,
      갱신 행 수가 0이면 경쟁 발생으로 간주해 클라이언트 단에서 재조회 → 재시도
    • UPDATE acct SET saldo = :new, row_version = row_version + 1 WHERE id = :id AND row_version = :old_version;
    • SERIALIZABLE을 유지해야 한다면 ORA-08177 캐치 후 짧은 지연 + 재시도를 표준화
      (트랜잭션은 짧고 작게 유지).
  4. 트랜잭션 범위 최소화 & 커밋 자주
    • 잠금/충돌 표면을 줄이면 ORA-08177 확률이 크게 감소
    • 읽기 전용 구간은 SET TRANSACTION READ ONLY 로 분리하는 것도 방법
  5. 업무적 직렬화 포인트 정립
    • 같은 키/범위를 다루는 코드 경로가 다중이라면, 항상 같은 순서로 자원 잠금(deadlock/충돌 감소)
    • 범위 기반 충돌(예: "남은 재고에서 선착순 차감")은 큐/작업자 한정, 시리얼라이저 테이블, 메시지 브로커 등 업무 흐름 자체를 직렬화하는 설계가 더 안전
728x90