여러 트랜잭션이 같은 데이터를 동시에 건드릴 때, 격리수준은 "다른 트랜잭션의 작업이 나에게 얼마나 보이는가"를 정합니다. 격리를 높이면 일관성이 올라가지만 동시성(성능)은 떨어집니다. 둘은 트레이드오프 관계입니다.
먼저 현재 값을 본다
SQL
-- MySQL
SELECT @@transaction_isolation; -- 기본 REPEATABLE-READ
-- PostgreSQL
SHOW default_transaction_isolation; -- 기본 read committed
4가지 격리수준과 막는 현상
낮은 수준일수록 이상 현상(anomaly)이 더 많이 발생합니다.
| 격리수준 | Dirty Read | Non-repeatable Read | Phantom Read |
|---|---|---|---|
| READ UNCOMMITTED | 발생 | 발생 | 발생 |
| READ COMMITTED | 막음 | 발생 | 발생 |
| REPEATABLE READ | 막음 | 막음 | 발생* |
| SERIALIZABLE | 막음 | 막음 | 막음 |
*MySQL InnoDB는 REPEATABLE READ에서 갭 락으로 팬텀까지 대부분 막습니다.
세 가지 현상이 뭔지부터
- Dirty Read — 아직 커밋 안 된 남의 변경을 읽음. 그 트랜잭션이 롤백하면 유령 데이터를 본 셈.
- Non-repeatable Read — 같은 행을 두 번 읽었는데 값이 다름(중간에 누가 UPDATE 커밋).
- Phantom Read — 같은 조건으로 두 번 조회했는데 행 개수가 다름(중간에 누가 INSERT).
직접 재현해 보기
세션 A에서 갱신하고 커밋 전, 세션 B에서 읽어봅니다.
SQL
-- 세션 B
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
BEGIN;
SELECT balance FROM accounts WHERE id = 1; -- A가 커밋해야 새 값 보임
COMMIT;
READ UNCOMMITTED로 바꾸면 세션 A가 커밋하기 전에도 변경값이 보입니다(dirty read).
어떤 수준을 쓸까
TEXT
- 대부분의 웹 서비스 → READ COMMITTED (PostgreSQL 기본)
- 일관된 스냅샷이 필요 → REPEATABLE READ (MySQL 기본)
- 정산·재고처럼 정확성 최우선 → SERIALIZABLE (성능 비용 감수)
기본값을 모르고 쓰다 "읽을 때마다 값이 바뀐다"는 증상을 만나면, 십중팔구 격리수준 이해 부족입니다.
트랜잭션 두 세션을 직접 띄워 dirty read·phantom read를 재현하는 실습은 데이터베이스 트랙에서 회원가입 없이 무료로 할 수 있습니다.