반응형
1. 동시성 문제의 본질
하나의 버튼 클릭이더라도
같은 데이터를 여러 사용자가 동시에 수정할 수 있다.
이때 중복 승인, 덮어쓰기, 상태 꼬임이 발생한다.
이걸 막는 방법이 락(lock) 이다.
2. 낙관적 락 (Optimistic Lock)
개념
- 충돌은 자주 발생하지 않는다는 가정
- 먼저 락을 걸지 않는다
- 업데이트 시점에만 충돌 여부를 검사
핵심 메커니즘
- row에 VERSION 컬럼을 둔다
- 업데이트 시 “내가 읽은 버전이 아직 유효한지” 확인
UPDATE loan SET status = 'APPROVED', version = version + 1 WHERE id = 1 AND version = 3;
- 성공(1 row) → 정상 처리
- 실패(0 row) → 누군가 먼저 수정함
특징
- DB 락을 오래 잡지 않음
- 성능 좋음
- 충돌 시 재시도 또는 에러 처리 필요
적합한 경우
- 승인/거절
- 게시글 수정
- 대부분의 웹 서비스
3. 비관적 락 (Pessimistic Lock)
개념
- 충돌이 자주 발생한다고 가정
- 아예 처음부터 다른 트랜잭션 접근 차단
구현 예
SELECT * FROM loan WHERE id = 1 FOR UPDATE;
- 트랜잭션 종료까지 row 락 유지
특징
- 중복 처리 확실히 방지
- 락 대기, 데드락 위험
- 트래픽 많으면 성능 저하
적합한 경우
- 재고 차감
- 계좌 이체
- 실시간 금액 변경
4. VERSION이란 무엇인가
정의
row가 몇 번째로 수정되었는지를 나타내는 값
- 업무 의미 없음
- 단순 증가
- 사람이 해석하지 않음
version = 1 → 최초 version = 2 → 첫 수정 version = 3 → 두 번째 수정
중요한 점
- JPA 전부터 존재하던 오래된 패턴
- JPA는 자동화했을 뿐, 개념을 만든 게 아님
5. VERSION은 어떻게 중복을 막는가
- A, B가 동시에 조회 (version = 3)
- A가 먼저 승인 → version 4로 증가
- B가 승인 시도
- WHERE version = 3 조건 불일치
- update 실패 → 충돌 감지
👉 DB가 최종 승자를 결정
6. update_dt로 대체하면 안 되는 이유 (요약)
- 시간 정밀도 문제
- 단조 증가 보장 없음
- 의미가 다름
컬럼역할
| version | 동시성 제어 |
| update_dt | 이력/감사 |
7. STEP으로 낙관적 락을 구현할 수 있는가?
결론부터
예외적으로 가능하지만, 완전한 대체는 아니다.
STEP으로 가능한 경우 (아주 제한적)
다음 조건을 모두 만족해야 한다.
- 단계가 단방향
- 절대 되돌아가지 않음
- 단계 수 고정
- 단일 테이블
- 단계 외 데이터 수정 없음
UPDATE loan SET step = 'APPROVED' WHERE id = 1 AND step = 'REVIEW';
이 경우:
- 사실상 version과 같은 패턴
- “부분적인 낙관적 락”이라고 볼 수 있음
8. STEP 기반 접근의 한계 (치명적)
1️⃣ STEP은 업무 의미다
- 기획이 바꿈
- 정책 변경 대상
- 불변이 아님
동시성 제어와 성격이 다르다.
2️⃣ STEP은 되돌아갈 수 있다
- 승인 취소
- 재심사
- 반려 후 재접수
이 순간 낙관적 락 전제가 깨진다.
3️⃣ 모든 변경을 감지하지 못한다
- 금액 수정
- 메모 수정
- 옵션 변경
STEP이 안 바뀌면 충돌을 못 잡는다.
4️⃣ 로직이 더러워진다
if (step != REVIEW) { throw new BusinessException(); }
- 동시성 제어가
- 서비스 로직에 퍼짐
- DB가 해야 할 일을 코드가 대신함
9. 실무 권장 구조
목적방법
| 동시성 제어 | version |
| 업무 흐름 | step |
| 이력/감사 | update_dt |
역할을 분리해야 안전하다.
10. 최종 결론
- 낙관적 락은 version 기반 조건 업데이트
- 비관적 락은 DB 락 선점
- STEP으로 낙관적 락을 “흉내” 낼 수는 있지만
- 범위 제한적
- 정책 변경에 취약
- 장기적으로 위험
STEP은 흐름이고,
VERSION은 안전장치다.
흐름으로 안전을 보장하려 하면 반드시 사고 난다.
반응형
'IT' 카테고리의 다른 글
| Spring @Transactional Propagation 완전 정리 (0) | 2025.12.15 |
|---|---|
| 외부 API 장애에도 우리 서비스가 죽지 않게 하는 방법 (0) | 2025.12.15 |
| 같은 서버에서 톰캣 별도 인스턴스 띄우기 (0) | 2025.12.11 |
| JSON 동적 필드 처리 – Jackson @JsonAnySetter 완전 이해하기 (0) | 2025.12.10 |
| RestTemplate 응답 타입에 따른 20초 타임아웃 트러블슈팅 (0) | 2025.12.04 |
댓글