CS Fundamentals
비관적 락과 낙관적 락의 차이에 대해서 설명해주세요
충돌을 미리 막을까, 나중에 검증할까? 비관적 락과 낙관적 락의 동작 원리를 인터랙티브 시뮬레이션으로 직접 체험하며 면접에서 완벽히 답할 수 있도록 준비합니다.
2026년 3월 15일 · 약 12분 읽기
Q. "비관적 락과 낙관적 락의 차이를 설명하고, 어떤 상황에서 각각을 선택하는지 말씀해주세요."
예상 꼬리질문
답변 가이드
"비관적 락은 '충돌이 날 것'이라 가정하고 데이터를 읽는 순간 배타 락을 획득해 다른 트랜잭션을 차단합니다. SELECT ... FOR UPDATE로 동작하며, 안전하지만 데드락 위험이 있습니다."
"낙관적 락은 '충돌이 드물 것'이라 가정하고 락 없이 작업한 뒤, 커밋 시점에 version 컬럼으로 충돌을 검증합니다. Spring Data JPA에서는 @Version 어노테이션 하나로 적용됩니다."
"선택 기준은 충돌률 약 20~30%가 임계점입니다. 선착순 이벤트나 금융 잔액처럼 충돌이 잦으면 비관적 락, 게시글·프로필 수정처럼 드물면 낙관적 락을 선택합니다."
재고가 1개 남은 상품을 100명이 동시에 구매하려 한다면, 데이터베이스는 어떻게 한 명에게만 성공시킬 수 있을까요?
동시성 문제를 해결하는 방법은 크게 두 가지입니다. 먼저 차단할 것인가, 아니면 일단 진행하고 나중에 검증할 것인가. 이 아티클에서는 두 전략의 동작 원리를 인터랙티브 시뮬레이션으로 직접 체험합니다.
1. 동시성 문제 — 왜 락이 필요한가
꼬리질문: "락이 없으면 어떤 문제가 발생하나요?"
여러 트랜잭션이 같은 데이터에 동시에 접근하면 Lost Update(갱신 손실) 문제가 발생합니다. T1이 재고 100개를 읽고 99개로 수정하는 사이, T2도 재고 100개를 읽어 99개로 수정하면, 결국 2번 차감됐어야 할 재고가 1번만 차감됩니다.
이 문제를 해결하기 위한 두 철학이 비관적 락과 낙관적 락입니다.
락 없이 동시 접근 시 발생하는 갱신 손실을 직접 확인해 보세요.
DB 재고 (stock)
products WHERE id=1
READ (stock=100)
SELECT stock FROM products WHERE id=1;
차감 계산 (100-1=99)
-- stock = 100 - 1 = 99
WRITE (stock=99)
UPDATE products SET stock=99 WHERE id=1;
COMMIT
COMMIT;
READ (stock=100)
SELECT stock FROM products WHERE id=1;
차감 계산 (100-1=99)
-- stock = 100 - 1 = 99
WRITE (stock=99)
UPDATE products SET stock=99 WHERE id=1;
COMMIT
COMMIT;
“락 없이 실행” 버튼을 눌러 두 트랜잭션이 충돌하는 과정을 확인하세요.
2. 비관적 락 — 먼저 차단하고 작업한다
꼬리질문: "비관적 락의 동작 원리와 단점을 설명해주세요"
비관적 락은 데이터에 접근하는 순간 배타 락(X-Lock)을 획득해 다른 트랜잭션을 차단합니다. SELECT ... FOR UPDATE 구문으로 동작하며, 락을 보유한 트랜잭션이 커밋 또는 롤백할 때까지 다른 트랜잭션은 대기합니다.
강력하지만 트레이드오프가 있습니다. 두 트랜잭션이 서로 상대방의 락을 기다리면 데드락(Deadlock)이 발생합니다. MySQL InnoDB는 순환 대기를 감지해 비용이 낮은 트랜잭션을 자동 롤백하지만, 설계 단계에서 락 획득 순서를 통일하는 것이 최선입니다.
비관적 락으로 동시 접근이 어떻게 차단되는지 시뮬레이션해 보세요.
DB 재고 (stock)
100row_id=1 Lock 상태
잠금 없음 (Free)
SELECT * FROM products WHERE id=1 FOR UPDATE;
SELECT * FROM products WHERE id=1 FOR UPDATE;
UPDATE products SET stock=99 WHERE id=1;
COMMIT;
-- T2 unblocked, lock acquired
UPDATE products SET stock=98 WHERE id=1;
COMMIT;
“단계별 실행”을 눌러 비관적 락의 흐름을 따라가세요.
3. 낙관적 락 — 작업 후 충돌을 검증한다
꼬리질문: "낙관적 락은 어떻게 충돌을 감지하나요?"
낙관적 락은 DB 락 없이 작업합니다. 대신 테이블에 version 컬럼을 추가하고, 커밋 시점에 WHERE id = ? AND version = ? 조건으로 내가 읽은 버전과 현재 DB 버전이 동일한지 확인합니다.
버전이 다르면 다른 트랜잭션이 먼저 수정한 것이므로 OptimisticLockException을 던지고 재시도합니다. Spring Data JPA에서는 @Version 어노테이션 하나로 버전 관리가 자동화됩니다.
낙관적 락의 버전 충돌 감지 과정을 시뮬레이션해 보세요.
stock
100version (DB)
5읽은 버전
SELECT stock, version FROM products WHERE id=1;
UPDATE products SET stock=99, version=6 WHERE id=1 AND version=5;
COMMIT;
SELECT stock, version FROM products WHERE id=1;
UPDATE products SET stock=99, version=6 WHERE id=1 AND version=5;
SELECT stock, version FROM products WHERE id=1;
UPDATE products SET stock=98, version=7 WHERE id=1 AND version=6;
COMMIT;
SQL 실행 로그
-- 아직 실행된 쿼리가 없습니다
“단계별 실행”을 눌러 version 컬럼으로 충돌을 감지하는 과정을 확인하세요.
4. 무엇을 선택할까 — 충돌률이 기준이다
꼬리질문: "두 방식 중 어떤 상황에서 무엇을 선택하나요?"
두 방식의 성능 차이는 충돌 빈도에 따라 역전됩니다. 충돌이 드문 환경에서는 낙관적 락이 블로킹 없이 빠르게 처리합니다. 하지만 충돌이 잦아지면 재시도가 폭발적으로 증가해 오히려 비관적 락보다 느려집니다.
일반적으로 충돌률 약 20~30%가 임계점입니다. 선착순 이벤트나 금융 잔액처럼 다수가 동일 row를 경쟁하면 비관적 락을, 게시글·프로필 수정처럼 충돌이 드문 경우엔 낙관적 락을 선택합니다.
충돌률에 따른 두 전략의 성능 비교를 직접 확인해 보세요.
상대적 처리량 (Throughput)
비관적 락 적합
- •선착순 한정 재고 구매
- •금융 계좌 잔액 차감
- •단일 처리 보장 작업
낙관적 락 적합
- •게시글 / 댓글 수정
- •사용자 프로필 업데이트
- •읽기 비중 90% 이상 서비스
슬라이더를 조정하여 충돌률에 따른 두 방식의 처리량 변화를 확인하세요.
면접 체크리스트
이 항목들을 자신 있게 설명할 수 있다면 락 질문은 준비 완료입니다.
- - 비관적 락: SELECT ... FOR UPDATE로 선점, 충돌 빈번 환경에 적합, 데드락 주의
- - 낙관적 락: @Version 컬럼으로 커밋 시 검증, 충돌 희박 환경에 적합, 재시도 로직 필요
- - 선택 기준: 충돌률 20~30% 이상이면 비관적 락, 미만이면 낙관적 락
- - 데드락 방지: 락 획득 순서를 항상 일관되게 유지
- - 분산 환경: DB 락만으로 부족하면 Redis 기반 분산 락(Redisson) 고려
참고 자료
- MySQL 8.0 공식 문서 — InnoDB Locking — InnoDB의 공유 락·배타 락·갭 락을 공식 문서로 확인
- Hibernate ORM 공식 문서 — Locking — JPA/Hibernate에서 비관적·낙관적 락을 적용하는 실용 가이드
- Redisson 공식 문서 — Distributed locks — 분산 환경에서 Redis 기반 락을 구현하는 방법
의견을 들려주세요
서비스 개선에 큰 도움이 됩니다. 익명으로 자유롭게 남겨주세요.