낙관적 잠금 vs 비관적 잠금 차이
한 줄 답변
낙관적 잠금은 버전 컬럼으로 수정 시점에 충돌을 감지하고, 비관적 잠금은 읽기 시점부터 SELECT FOR UPDATE로 잠금을 선점합니다.
핵심 개념 정리
낙관적 잠금(Optimistic Lock)과 비관적 잠금(Pessimistic Lock)은 동시성 환경에서 데이터 무결성을 보장하기 위한 두 가지 핵심 전략입니다. 두 방식은 '충돌이 얼마나 자주 발생하는가'에 대한 가정에서 출발점이 다르며, 선택에 따라 성능과 안전성 간의 트레이드오프가 뚜렷하게 달라집니다.
낙관적 잠금은 충돌이 드물다고 가정하고, 데이터 읽기 시 잠금을 걸지 않습니다. 테이블에 version(Long) 또는 updated_at 컬럼을 추가하고, UPDATE 시점에 WHERE version = :읽어온버전 조건을 추가해 동시 변경을 감지합니다. JPA에서는 @Version 어노테이션 하나로 구현 가능하며, 충돌 발생 시 OptimisticLockException이 던져집니다. 잠금 없이 읽기가 이루어지므로 처리량이 높지만, 충돌 빈도가 높아질수록 재시도 로직의 오버헤드가 누적되는 단점이 있습니다.
비관적 잠금은 충돌이 빈번하다고 가정하여, 데이터 조회 시점부터 DB 레벨 잠금을 획득합니다. MySQL의 SELECT ... FOR UPDATE 구문이 대표적이며, JPA에서는 LockModeType.PESSIMISTIC_WRITE로 설정합니다. 트랜잭션 종료 전까지 다른 트랜잭션의 쓰기 접근을 차단하므로 데이터 일관성이 강하게 보장됩니다. 단점은 잠금 대기로 인한 처리량 저하와 데드락 발생 위험입니다.
실무 선택 기준은 충돌 빈도와 비즈니스 요구사항입니다. SNS 좋아요·게시판 조회수처럼 동시 수정 가능성이 낮은 케이스는 낙관적 잠금이 유리하고, 재고 차감·포인트 적립처럼 정확성이 최우선이고 경합이 심한 케이스는 비관적 잠금이 적합합니다. 분산 MSA 환경에서는 단일 DB 잠금의 한계로 인해 Redis SETNX 기반 분산 락(Redisson)을 추가로 고려해야 합니다.
비교 정리
| 항목 | 낙관적 잠금 | 비관적 잠금 |
|---|---|---|
| 충돌 가정 | 충돌이 드물다고 가정, 잠금 없이 읽기 수행 | 충돌이 빈번하다고 가정, 읽기 시점부터 잠금 획득 |
| 구현 방법 | @Version 컬럼 + OptimisticLockException 핸들링 | SELECT FOR UPDATE / LockModeType.PESSIMISTIC_WRITE |
| 성능 특성 | 읽기 처리량 우수, 충돌 시 재시도 오버헤드 발생 | 일관성 강하지만 잠금 대기로 처리량 저하 가능 |
| 데드락 위험 | 잠금 미사용으로 데드락 발생하지 않음 | 잠금 획득 순서 불일치 시 데드락 위험 존재 |
| 적합 사례 | SNS 좋아요, 조회수 증가 등 경합이 낮은 도메인 | 재고 차감, 계좌 이체 등 정확성이 최우선인 도메인 |
면접에서 이렇게 답하세요
면접에서는 먼저 두 방식의 핵심 가정 차이(충돌 빈도)를 명확히 구분한 뒤, 각 구현 방법과 트레이드오프를 순서대로 설명하세요. JPA @Version과 LockModeType.PESSIMISTIC_WRITE 코드 레벨 지식을 언급하면 깊이를 어필할 수 있습니다. 실무 경험을 묻는다면 '재고 차감 로직에서 동시 주문 경쟁 상황에 비관적 잠금을 도입해 overselling을 방지한 경험'처럼 구체적인 도메인 사례로 답하세요. 낙관적 잠금 충돌 처리에 Spring @Retryable 활용을 추가로 언급하면 차별화 포인트가 됩니다.
자주 묻는 추가 질문
Q. 낙관적 잠금에서 충돌이 발생하면 어떻게 처리하나요?
OptimisticLockException을 캐치한 뒤 Spring Retry의 @Retryable로 자동 재시도하거나, 사용자에게 재요청을 안내하는 방식으로 처리합니다.
Q. 비관적 잠금에서 데드락을 어떻게 예방하나요?
애플리케이션 전역에서 잠금 획득 순서를 통일하고, innodb_lock_wait_timeout 설정으로 대기 시간을 제한해 데드락 발생을 방지합니다.
Q. 분산 환경에서 낙관적·비관적 잠금만으로 부족한 이유는?
DB가 분리된 MSA 환경에서는 단일 DB 잠금이 서비스 간 적용되지 않아 Redis SETNX 기반 분산 락이나 Redisson 라이브러리를 별도 도입해야 합니다.
커뮤니티 하이라이트
“재고 서비스에서 낙관적 잠금만 썼다가 flash sale 때 overselling이 터진 경험이 있어요. 충돌 빈도 사전 예측이 선택의 핵심입니다.”
“@Version 쓸 때 JPQL 벌크 UPDATE는 버전 자동 증가가 안 돼서 수동으로 version+1 처리해야 한다는 것도 면접에서 종종 나와요.”
32명의 개발자가 이 질문에 참여했습니다
관련 면접 질문
앱에서 직접 답변해보세요
매일 3개의 면접 질문에 답변하고,
다른 개발자들의 답변을 비교해보세요.