# 03-04. 격리 수준(MySQL)

## **Q. MySQL 격리 수준에 대해서 설명해주세요.**

MySQL에서 격리 수준(isolation level)은 트랜잭션이 다른 트랜잭션의 작업에 얼마나 영향을 받지 않고 독립적으로 실행될 수 있는지를 정의하는 개념입니다. MySQL는 표준 SQL에서 정의된 4가지 격리 수준을 지원하는데,

먼저, `Read Uncommitted`이 있습니다. 이 수준에서는 한 트랜잭션이 커밋되지 않은 데이터를 다른 트랜잭션에서 읽을 수 있습니다. 흔히 `'더티 리드(Dirty Read)'`라고 부르는 문제가 발생할 수 있는데, 성능은 좋아지겠지만 데이터의 일관성이 떨어질 수 있습니다. 그래서 실무에서는 거의 사용되지 않는다고 합니다.

다음으로 `Read Committed`가 있습니다. 이 격리 수준에서는 커밋된 데이터만 읽을 수 있어서 더티 리드는 방지되지만, 같은 트랜잭션 내에서 데이터를 여러 번 읽을 때 값이 달라질 수 있는 `'논-리피터블 리드(Non-repeatable Read)'` 문제가 생길 수 있습니다. MySQL 실무에서 꽤 자주 사용된다고 합니다.

세 번째로 `Repeatable Read`가 있습니다. 이건 MySQL의 기본 격리 수준인데, 트랜잭션 시작 시점의 데이터를 고정해서 읽기 때문에 논-리피터블 리드는 방지됩니다. 하지만 새로운 데이터가 추가되는 경우, 즉 `'팬텀 리드(Phantom Read)'`는 여전히 발생할 가능성이 있습니다. InnoDB 엔진에서는 멀티 버전 동시성 제어(MVCC)를 사용해서 이 문제를 어느 정도 완화해줍니다.

마지막으로 `Serializable`이 있습니다. 이 수준은 트랜잭션을 완전히 직렬화해서 실행하기 때문에 모든 동시성 문제가 해결됩니다. 팬텀 리드까지 방지할 수 있어서 데이터 일관성이 가장 높지만, 그만큼 성능이 많이 떨어질 수 있어요. 그래서 보통 극단적인 일관성이 필요한 상황에서만 사용된다고 합니다.

## **Q. Repeatable Read에서 팬텀 리드가 발생할 수 있다고 했는데, 실제로 어떤 상황에서 문제가 될 수 있을까요?**

`Repeatable Read`에서 `팬텀 리드(Phantom Read)`가 발생할 수 있다는 건, 트랜잭션 도중에 다른 트랜잭션이 새로운 데이터를 추가하거나 삭제해서 결과 집합이 달라질 수 있다는 것 입니다.

호텔 예약 시스템을 예로 든다면,

1. 트랜잭션 A가 "특정 날짜에 예약 가능한 방"을 조회합니다. 여기서 결과로 3개 방이 나왔다고 합시다.
2. 트랜잭션 A가 이 3개 중 하나를 예약하려고 준비 중인데,
3. 그 사이 트랜잭션 B가 새 방을 추가하거나 취소된 예약을 풀어서 예약 가능 방이 4개가 돼요.
4. 트랜잭션 A가 다시 쿼리를 날리면 4개 방이 보이고, 처음 3개만 있다고 가정한 로직이 있다면 이 로직은 깨질 수 있습니다.

\
보통 이런 실시간성이 들어가는 경우 팬텀 리드 문제가 발생할 수 있기 때문에, 데이터가 실시간으로 정확해야하는 경우 격리수준을 `Serializable`로 올리는게 합당합니다.
