백엔드 면접 용어 사전
데이터베이스pessimistic lock

비관적 락

충돌을 가정해 미리 잠그는 전략. SELECT … FOR UPDATE가 대표적이며 경쟁이 심할 때 유리하다.

"충돌이 일어날 것"이라고 가정하고 미리 잠그는 전략(pessimistic lock).

방법

BEGIN;
SELECT * FROM stock WHERE id = 1 FOR UPDATE;   -- 배타 락 획득
-- 이 순간부터 다른 트랜잭션은 이 행을 수정할 수 없다(대기)
UPDATE stock SET qty = qty - 1 WHERE id = 1;
COMMIT;                                         -- 락 해제
구문락 종류다른 트랜잭션이
FOR UPDATE배타 락(X)읽기도 쓰기도 대기
FOR SHARE공유 락(S)읽기는 가능, 쓰기는 대기

JPA에서는 @Lock(LockModeType.PESSIMISTIC_WRITE) 로 건다.

언제 유리한가 — 경쟁이 심할 때

낙관적 락은 충돌하면 되돌리고 재시도한다. 경쟁이 심하면 재시도가 폭증한다.

인기 상품 재고 차감, 동시 요청 100건 낙관적 락 → 1건 성공, 99건 실패 → 재시도 → 1건 성공, 98건 실패 → …

  • 총 시도 횟수가 5000회에 육박 비관적 락 → 100건이 순서대로 대기하며 처리. 시도는 100회

대가와 위험

① 대기가 처리량을 떨어뜨린다 락을 쥔 시간만큼 다른 요청이 멈춘다. → 트랜잭션을 최대한 짧게. 특히 락을 쥔 채 외부 API를 호출하면 최악이다.

② 데드락 여러 행을 잠글 때 순서가 엇갈리면 서로를 기다린다.

T1: A 잠금 → B 요청
T2: B 잠금 → A 요청     ← 교착

항상 같은 순서로 잠그면 크게 줄어든다(예: id 오름차순).

③ 락 타임아웃 무한 대기를 막기 위해 innodb_lock_wait_timeout(기본 50초)이 있다. 운영에서는 더 짧게 잡아 빨리 실패시키는 편이 낫다.

인덱스가 없으면 테이블 전체가 잠긴다 — 중요한 함정

InnoDB의 행 락은 인덱스 레코드에 걸린다.

SELECT * FROM orders WHERE memo = 'x' FOR UPDATE;   -- memo에 인덱스가 없다면?
→ 풀스캔하며 훑은 모든 행에 락 → 사실상 테이블 락

락을 걸 컬럼에 인덱스가 있는지 반드시 확인해야 한다.

면접 답변 골격

"경쟁 정도로 고릅니다. 충돌이 드물면 낙관적 락으로 대기를 없애고, 한 행에 몰리는 구간은 비관적 락으로 재시도 폭증을 막습니다. 어느 쪽이든 트랜잭션을 짧게 하고 락 컬럼에 인덱스가 있는지 확인하는 것이 전제입니다."

함께 보면 좋은 용어

노트에서 맥락과 함께 보기 — 데이터베이스 — 인덱스·트랜잭션·격리수준·N+1