DATABASE

트랜잭션 격리 수준 4단계

algml0703 2026. 6. 1. 21:52
반응형
트랜잭션에서 격리 수준이란 여러 트랜잭션이 동시에 같은 데이터를 다룰 때, 한 트랜잭션이 다른 트랜잭션의 작업을 얼마나 볼 수 있는지(=얼마나 격리되는지)를 정하는 단계 설정을 의미한다. 격리 수준은 4단계로 나뉘며높일수록 안전하지만 느리고, 낮출수록 빠르지만 위험하다.

트랜잭션 격리 수준이 존재하는 이유

여러 트랜잭션을 완벽하게 격리하면(서로 영향을 0으로) 가장 안전하지만 동시 처리량이 바닥난다. 반대로 격리를 풀면 빠르지만 데이터가 꼬인다. 격리 수준은 이 안전성과 성능 사이의 트레이드오프를 조절하는 장치다.

즉 격리 수준은 어떤 동시성 문제(이상 현상)를 허용하고 어떤 걸 막을 것인가를 정하는 것이라 할 수 있다. 격리 수준과 관련하여 3가지 타입의 이상 현상이 존재한다.

이상 현상

  • Dirty Read (더티 리드) — 아직 커밋되지 않은 데이터를 읽는 것. 옆 트랜잭션이 값을 바꿔놨는데 그게 롤백되면, 나는 존재한 적도 없는 유령 값을 읽은 셈이 된다.
  • Non-Repeatable Read (반복 불가능한 읽기) — 한 트랜잭션 안에서 같은 행(row)을 두 번 읽었는데 값이 달라지는 것. 내가 두 번 읽는 사이에 다른 트랜잭션이 그 행을 수정(UPDATE)하고 커밋했기 때문이다.
  • Phantom Read (팬텀 리드) — 한 트랜잭션 안에서 같은 조건의 범위 쿼리를 두 번 실행했는데 결과 행의 개수가 달라지는 것. 그 사이 다른 트랜잭션이 조건에 맞는 새 행을 INSERT(또는 DELETE)했기 때문이다.

4단계 격리 수준

낮은 수준에서 높은 수준으로 갈수록 차단하는 이상 현상이 늘어난다.

격리 수준 Dirty Read Non-Repeatable Phantom
Read Uncommitted 발생 발생 발생
Read Committed 차단 발생 발생
Repeatable Read 차단 차단 발생
Serializable 차단 차단 차단

* 표준 정의 기준. MySQL InnoDB는 구현상 대부분 방지한다(아래 참고).

Read Uncommitted

커밋되지 않은 데이터까지 읽어 Dirty Read가 발생한다. 사실상 격리를 거의 하지 않는 수준이라 실무에서 거의 쓰지 않는다.

Read Committed

커밋된 데이터만 읽으므로 Dirty Read는 막는다. 하지만 한 트랜잭션 안에서 같은 행을 다시 읽을 때 그 사이 수정·커밋된 값을 읽으므로 Non-Repeatable Read가 발생할 수 있다. Oracle, PostgreSQL, SQL Server의 기본값이다.

Repeatable Read

한 트랜잭션이 시작된 시점의 데이터를 일관되게 보여줘, 같은 행을 몇 번 읽어도 동일한 값을 보장한다. 표준 정의상으로는 새 행이 INSERT되는 Phantom Read가 남는다. MySQL InnoDB의 기본값이다.

Serializable

가장 엄격한 수준으로, 모든 트랜잭션을 마치 한 줄로 세워 차례대로 실행한 것과 같은 결과를 보장한다. 세 이상 현상을 모두 막지만, 그만큼 잠금 범위가 넓어져 동시성이 크게 떨어진다.

격리 구현 방법

격리는 잠금 또는 MVCC로 구현

격리를 구현하는 방식은 크게 두 가지다. 잠금(Lock) 기반은 데이터를 잠가 다른 트랜잭션의 접근을 막는 것이고, MVCC(다중 버전 동시성 제어)는 데이터를 잠그는 대신 버전별 스냅샷을 따로 두어, 읽기와 쓰기가 서로를 막지 않게 하는 것이다.

Oracle, PostgreSQL, MySQL InnoDB 모두 MVCC를 활용해 높은 동시성을 확보한다. 

반응형