Dirty Read / Phantom Read
트랜잭션 이상 현상 3가지
[Dirty Read]
TX1: UPDATE balance = 0 (커밋 전)
TX2: SELECT balance → 0 ← 커밋 안 된 값 읽음!
TX1: ROLLBACK ← 원래 1000원인데...
→ TX2는 존재하지 않는 데이터를 읽은 것
[Non-Repeatable Read]
TX1: SELECT age → 25
TX2: UPDATE age = 26, COMMIT
TX1: SELECT age → 26 ← 같은 TX인데 값 변경!
→ 같은 쿼리, 다른 결과
[Phantom Read]
TX1: SELECT COUNT(*) → 10건
TX2: INSERT 1건, COMMIT
TX1: SELECT COUNT(*) → 11건 ← 유령 행 출현!
→ 없던 행이 생김
격리 수준별 방지
| 격리 수준 | Dirty | Non-Repeatable | Phantom |
|---|---|---|---|
| READ UNCOMMITTED | X | X | X |
| READ COMMITTED | O | X | X |
| REPEATABLE READ | O | O | X* |
| SERIALIZABLE | O | O | O |
*MySQL InnoDB는 REPEATABLE READ에서도 Gap Lock으로 Phantom Read 방지
실무 선택 가이드
대부분의 웹 서비스
→ READ COMMITTED (PostgreSQL 기본)
→ REPEATABLE READ (MySQL 기본)
금융/결제 시스템
→ SERIALIZABLE 또는 명시적 락
통계/리포트 조회
→ READ UNCOMMITTED도 가능
(정확도 < 성능)
면접 포인트
"실무에서 어떤 격리 수준을 쓰나요?"
MySQL: REPEATABLE READ (기본값, Gap Lock으로 Phantom도 방지) PostgreSQL: READ COMMITTED (기본값, MVCC로 성능 확보) 결제처럼 정확성이 중요한 경우 SELECT ... FOR UPDATE 사용