자주 사용되는 MariaDB의 READ COMMITTED와 REPEATABLE READ의 차이는 무엇이고, 어떤 문제가 각각 발생할 수 있을까?
🔍 READ COMMITTED
- 항상 "커밋된 최신 데이터"를 조회한다.
- 다른 트랜잭션에서 커밋된 최신 결과가 반영됨
발생 가능한 문제:
- ❗ Non-Repeatable Read → 같은 row를 두 번 조회했을 때 중간에 다른 트랜잭션이 값을 바꾸면 다른 값이 반환됨
- ❗ Phantom Read → 같은 조건으로 select했을 때 중간에 insert(커밋)된 row로 인해 row 개수가 달라짐
- ❗ Lost Update → 두 트랜잭션이 같은 데이터를 수정하고 한 쪽이 덮어쓰는 문제
🔍 REPEATABLE READ (MariaDB의 기본 설정)
- 트랜잭션 시작 시점의 커밋된 데이터를 기준으로 스냅샷을 생성하고 트랜잭션이 커밋될 때까지 고정됨
방지되는 문제:
- ✅ Non-Repeatable Read 방지 → 한 번 읽은 row는 트랜잭션 내에서 계속 같은 값을 유지
- ✅ Phantom Read 방지 (MariaDB) → 인덱스 범위까지 스냅샷으로 관리되므로, 중간에 삽입된 row도 보이지 않음
- ❗ 단, Lost Update는 여전히 발생 가능 → 단순 select만 수행한 경우 락이 걸리지 않기 때문에, 커밋 시점이 다른 경우 발생 할 수 있음
격리 수준이 높아질수록 읽기의 일관성은 보장되지만, 쓰기 간 충돌(Lost Update)을 완전히 막지는 못한다.
| 부정합 문제 | READ COMMITTED | REPEATABLE READ |
| Dirty Read | 방지됨 | 방지됨 |
| Non-Repeatable Read | 방지됨 | 방지됨 |
| Phantom Read | 발생 가능 | 방지됨 |
앞서 발생한 lost update를 READ COMMITTED, REPEATABLE READ 격리 수준에서 각각 설명하면 다음과 같다
| 설명 | READ COMMITTED | REPEATABLE READ | |
| 1 | 트랜잭션 A가 객체 단순 조회 (SELECT) | 커밋된 최신 데이터 읽음 | 스냅샷 생성 (트랜잭션 시작 시점 기준 커밋된 데이터) |
| 2 | 트랜잭션 B도 객체 단순 조회 | 동일하게 커밋된 최신 데이터 읽음 | 동일하게 스냅샷 기준 데이터 읽음 |
| 3 | 트랜잭션 B가 먼저 커밋 | 커밋 가능 (락 없음) | 커밋 가능 (락 없음) |
| 4 | 트랜잭션 A가 커밋 (JPA 더티 체킹) | B의 변경사항을 덮어씀 → ❗ Lost Update | B의 변경사항을 덮어씀 → ❗ Lost Update |
| 🔁 (4-1) | A가 커밋 전 같은 객체를 다시 조회한 경우 | 다른 값 조회됨 (다른 트랜잭션 커밋 반영됨) | 처음 조회한 값 그대로 유지됨 (스냅샷 기반) |
| ✅ 특징 | 커밋된 최신값을 매번 참조 | 트랜잭션 내 조회 결과 고정 |
'TWIL' 카테고리의 다른 글
| [3기] 잇츠 스터디 (IT’s Study Crew) : TWIL 스터디 회고 (0) | 2025.04.27 |
|---|---|
| Spring @Transactional - 프록시 기반 동작방식과 예외상황재현 테스트 (0) | 2025.04.13 |
| JPA 더티체킹 사용시 주의할점 : REPEATABLE READ 격리 수준에서 발생한 동시성문제 해결하기 (1) | 2025.03.22 |
| Spring Cloud Stream으로 Kafka 메시지 처리하기 - 1 (0) | 2025.03.17 |
| API 성능 최적화하기 - 1 (2) | 2025.03.16 |