콘텐츠로 이동

select for update와 serializable 격리수준

1. 직렬화 가능 고립(Serializable Isolation)의 개념

  • 정의: 여러 트랜잭션이 동시에 실행되더라도, 마치 한 번에 하나씩 순차적으로(직렬로) 실행된 것과 같은 결과를 보장하는 가장 높은 단계의 고립 레벨입니다.
  • 목표: 데이터의 일관성을 완벽하게 유지하는 것입니다.

2. 구현 방식 비교: 비관적 vs 낙관적

① 비관적 동시성 제어 (Pessimistic Concurrency Control)

  • 작동 방식: SELECT FOR UPDATE 등을 사용하여 데이터에 독점 잠금(Exclusive Lock)을 겁니다.
  • 10개의 트랜잭션이 오면, 1개가 잠금을 획득하고 나머지 9개는 대기(Blocking)합니다.
  • 첫 번째가 끝나면 두 번째가 잠금을 얻는 식으로 하나씩 처리합니다.
  • 장점: 트랜잭션이 실패할 확률이 거의 없습니다. 구현이 단순하고 로직이 명확합니다.
  • 단점: 동시성과 처리량(Throughput)이 현저히 떨어집니다. 모든 작업이 줄을 서야 하므로 속도가 느려집니다.

② 낙관적 동시성 제어 (Optimistic Concurrency Control)

  • 작동 방식: "서로 방해하지 않을 것"이라고 가정하고 잠금 없이 일단 실행합니다.
  • 커밋 시점에 데이터베이스가 다른 트랜잭션에 의해 데이터가 변경되었는지(충돌 여부)를 감지합니다.
  • 충돌이 발견되면 해당 트랜잭션을 실패시키고 오류를 반환합니다.
  • 장점: 여러 트랜잭션이 동시에 실행될 수 있어 병렬성과 속도가 유지됩니다.
  • 단점: 충돌 발생 시 트랜잭션이 실패하므로, 애플리케이션 레벨에서 '재시도(Retry) 로직'을 구현해야 하는 번거로움이 있습니다.

3. 요약 및 선택 기준 (Trade-off)

구분 비관적 제어 (SELECT FOR UPDATE) 낙관적 제어 (Serializability 체크)
핵심 철학 "충돌할 것이 뻔하니 미리 잠그자" "충돌 안 할 것 같으니 일단 가보자"
동시성 낮음 (차단 발생) 높음 (병렬 실행)
실패 가능성 낮음 (기다리면 성공함) 있음 (충돌 시 실패 및 재시도 필요)
복잡성 단순함 복잡함 (재시도 로직 필요)

결론: 무엇을 선택해야 하는가?

  • 비관적 제어 권장: 동시 요청이 많지 않거나, 데이터 무결성이 절대적으로 중요하며 재시도 로직을 만들기 싫은 경우.
  • 낙관적 제어 권장: 동시 요청이 매우 많고 빠른 응답 속도가 중요하며, 충돌이 빈번하게 발생하지 않을 것이라고 예상되는 경우.