목록으로 돌아가기

낙관적 락(Optimistic Locking)

2025년 12월 20일
1개 태그
optimistic lock

낙관적 락(Optimistic Locking)

낙관적 락은 충돌이 적을 때 사용하는 방식입니다. 비관적 락과 달리 읽기 시 락을 걸지 않고, 저장 시 버전을 확인해 충돌을 감지합니다.

현재 구현 분석

1. Version 필드 추가


@Version
@Column("version")
var version: Long = 0

- @Version: Spring Data R2DBC가 자동으로 버전 관리
- 읽기 시: 현재 version 값을 함께 조회
- 저장 시: WHERE 절에 version 조건 추가
- 성공 시: version 자동 증가
  • @Version: Spring Data R2DBC가 자동으로 버전 관리

  • 읽기 시: 현재 version 값을 함께 조회

  • 저장 시: WHERE 절에 version 조건 추가

  • 성공 시: version 자동 증가 2. 동작 원리

    • 저장 시 실행되는 쿼리 (개념적)

UPDATE credit_balances
SET balance = 150, version = version + 1, updated_at = NOW()
WHERE id = 'xxx' AND version = 1 -- 읽었던 version과 일치해야 함
- 만약 다른 트랜잭션이 먼저 업데이트했다면
-- version이 2로 변경되어 있으므로 WHERE 조건이 실패
-- → 0 rows affected → OptimisticLockingFailureException 발생

다이어그램

시나리오 1: 정상적인 경우 (충돌 없음)

다이어그램 로딩 중...

시나리오 2: 동시성 충돌 발생 및 재시도

다이어그램 로딩 중...

전체 프로세스 플로우

다이어그램 로딩 중...

데이터베이스 상태 변화

다이어그램 로딩 중...

코드에서의 동작

1. Entity에 Version 필드

다이어그램 로딩 중...
  • R2DBC가 자동으로 버전 관리
  • 저장 시 WHERE 절에 version 조건 추가 2. 재시도 메커니즘
다이어그램 로딩 중...
  • Retry.backoff: 지수 백오프 재시도
  • filter: OptimisticLockingFailureException만 재시도
  • Mono.defer: 재시도마다 최신 잔액 재조회 3. 트랜잭션 원자성
다이어그램 로딩 중...
  • 잔액 저장과 거래 내역 저장을 하나의 트랜잭션으로 묶음
  • 하나라도 실패하면 전체 롤백

장점과 단점

장점

  • 읽기 성능: 읽기 시 락 없음
  • 동시성: 여러 읽기 동시 처리 가능
  • 데드락 방지: 락 대기 없음

단점

  • 충돌 시 재시도 필요: 성능 오버헤드
  • 최종 실패 가능: 재시도 한도 초과 시
  • 복잡도: 재시도 로직 필요

실제 동작 예시

시나리오: 두 사용자가 동시에 크레딧 차감

다이어그램 로딩 중...

핵심 포인트

  1. Version 필드: 각 업데이트마다 자동 증가
  2. WHERE 조건: 저장 시 읽었던 version과 일치해야 성공
  3. 충돌 감지: version 불일치 시 OptimisticLockingFailureException
  4. 재시도: 최신 version으로 다시 시도
  5. 원자성: TransactionalOperator로 잔액+거래 내역을 하나의 트랜잭션으로 처리

댓글 (0)

댓글 수정 시 필요합니다. 최소 4자 이상 입력해주세요.

아직 댓글이 없습니다. 첫 번째 댓글을 작성해보세요!