SELECT는 잠금 없는 consistent read라 스냅샷만 읽고 다른 트랜잭션의 수정을 막지 못함FOR SHARE / FOR UPDATE와 수식어 NOWAIT / SKIP LOCKED(8.0+)를 제공FOR UPDATE 불가FOR SHARE 보유 가능LOCK IN SHARE MODEUPDATE처럼 취급FOR SHARE·FOR UPDATE를 모두 차단SELECT * FROM account WHERE id = 1 FOR UPDATE; -- 이 행을 잠그고 최신값 읽기
SELECT): MVCC 스냅샷을 읽음, 잠금 없음FOR UPDATE/FOR SHARE/UPDATE/DELETE): 최신 커밋 버전을 읽고 잠금SELECT와 다름SELECT id FROM jobs
WHERE status = 'ready'
ORDER BY id
LIMIT 10
FOR UPDATE SKIP LOCKED; -- 안 잠긴 작업 10개만 원자적으로 선점
SKIP LOCKED로 정확히 “원하는 행만” 잠그려면 인덱스를 태우거나 READ COMMITTED를 쓰는 게 유리FOR UPDATE SKIP LOCKED LIMIT n으로 서로 겹치지 않는 행 집합을 비차단으로 선점FOR UPDATE/FOR SHARE + NOWAIT/SKIP LOCKED)과 SKIP LOCKED의 기본 의미는 거의 동일하나, 내부 동작은 다름| 구분 | MySQL (InnoDB) | PostgreSQL |
|---|---|---|
| 기본 격리수준 | REPEATABLE READ | READ COMMITTED |
| 갭·next-key 락 | 있음 (RR에서 phantom 방지) | 없음 (직렬화는 SERIALIZABLE의 SSI predicate lock) |
| locking read 충돌 시 | current read로 최신 읽고 블록(대기) | RR/SERIALIZABLE이면 직렬화 에러→재시도, RC면 대기 후 최신 재평가 |
| MVCC 저장 | undo log로 이전 버전 재구성 | heap에 다중 버전 보관(+ VACUUM 정리) |
| 행 잠금 모드 | FOR UPDATE / FOR SHARE (2종) | FOR UPDATE / FOR NO KEY UPDATE / FOR SHARE / FOR KEY SHARE (4종) |
| SKIP LOCKED / NOWAIT | 8.0+ | 9.5+ |
SKIP LOCKED가 갭 락과 얽힘. PostgreSQL은 갭 락 자체가 없어 매칭된 행만 잠금FOR KEY SHARE/FOR NO KEY UPDATE로 잠금 모드를 더 세분화