DB

[DB] 트랜잭션 격리수준 (Isolation level)

kittity 2025. 2. 6. 18:58

트랜잭션이란 데이터베이스의 상태를 변화시키기 위한 일련의 작업 단위로 ACID(원자성, 일관성, 독립성, 지속성)의 특징을 갖는다. 

 

ACID에 대해 간략히 정리하면 다음과 같다. 

  • Atomicity (원자성) - 트랜잭션의 모든 쿼리가 DB에 반영되거나, 모두 반영되지 않아야 한다.
  • Consistency (일관성) - 트랜잭션 처리 결과는 항상 일관성이 있어야 한다.
  • Isolation (독립성) - 서로 다른 트랜잭션을 서로의 연산에 개입할 수 없다.
  • Durability (지속성) - 트랜잭션이 성공적으로 처리되었다면 결과는 영구 반영되어야 한다.

 

트랜잭션 격리 수준은 여러 트랜잭션이 동시에 처리될 때, 특정 트랜잭션이 변하거나 조회하는 데이터를 다른 트랜잭션에서 볼 수 있게 허용할지 여부를 결정하는 것이다. 트랜잭션 격리 수준은 DB 마다 다르며, MySQL 기준으로 4개가 있다. 격리 수준이 높은대로 Serializable, Repeatable Read, Read Committed, Read Uncommitted가 존재한다.

 

 

각각의 격리 수준과 격리 수준에 따라 발생할 수 있는 문제에 대해 알아보자. 

 

1. Serializable

Serializable은 가장 엄격한 격리 수준으로 트랜잭션을 순차적으로 진행시킨다. 트랜잭션이 동시에 동일한 레코드에 접근이 불가능하기 때문에 데이터의 부정합 문제는 발생하지 않는다. 따라서 트랜잭션이 동기적으로 수행되기 때문에 처리속도 저하가 발생한다. 

순수한 SELECT 작업에서도 읽기잠금(공유락)을 건다. 따라서 공유락을 획득해 조회한 후 쓰기잠금을 통해 Update를 하려고할때 서로 다른 트랜잭션간 개입할 경우 대기상태가 되므로 데드락 문제가 발생한다. 참고로, 공유락을 걸면 배타락을 걸 수 없다. (공유락과 배타락에 대해서는 이전 포스팅을 참고하면 된다.)

 

2. Repeatable Read (반복 가능한 읽기)

Repeatable Read는 커밋된 데이터만 읽을 수 있으며, 자신보다 빨리 수행된 트랜잭션에서 커밋한 데이터만을 읽을 수 있는 격리수준이다. MVCC의 Undo 로그를 기반으로한 트랜잭션 내에서 동일한 데이터가 조회되도록 보장하지만, 새로운 데이터가 추가되는 경우에는 부정합이 생길 수 있다. 이를 지원하지 않는 DB에서는 배타락을 통해 해결할 수 있다. 

 

Repeatable Read에서는 Phantom Read(유령 읽기) 문제가 발생할 수 있다. 

Phantom Read는 하나의 트랜잭션 내에서 동일한 SELECT 쿼리를 실행했을 때 그 결과의 레코드 수가 달라지는 현상이다. 락이 걸린 읽기는 데이터 조회가 언두 로그가 아닌 테이블에서 수행되기 때문이다. 

 

예를 들어, A 트랜잭션에서 SELECT 하고 로직을 수행하는 동한 B 트랜잭션에서 INSERT를 했다면 A 트랜잭션에서 다시 SELECT를 할경우 레코드 수가 증가된다. 

 

참고로, MySQL에서는 Phantom Read가 발생하지 않는다. 그 이유는 InnoDB 엔진에서 select ~ for update 구문(배타락)을 지원하기 때문이다. 

 

3. Read Committed (커밋된 읽기)

Read Committed는 커밋된 데이터에만 접근할 수 있게하는 격리 수준이다.

 

이 경우에는 Phantom Read에 더해 Non-Repeatable Read 문제가 발생한다. 이는 반복 읽기가 불가능한 것으로, 하나의 트랜잭션에서 동일한 SELECT 쿼리를 실행했을 때 한번은 커밋 전의 데이터가 조회되고 이후 에는 커밋 된 후의 데이터가 조회되어 다른 결과가 조회되는 현상이다. 

 

4. Read Uncommitted (커밋되지 않은 읽기)

Read Uncommitted는 커밋되지 않은 데이터에도 접근할 수 있게 해주는 격리 수준이다. 

 

이때는 Dirty Read 문제가 발생할 수 있다. Dirty Read는 커밋되지 않은 트랜잭션에 접근해 아직 정상적으로 반영되지 않은 데이터를 읽는 현상이다. 이때, 문제는 해당 데이터가 롤백되어 없어질 수 있다는 것이다.

 

 

DB 트랜잭션 격리 수준은 DB마다 정의하는게 다르고 서비스마다 적용해야하는 수준이 다를 수 있다. 참고로 Oracle에서는 Read Committed를 기본으로 사용하며, MySQL에서는 Repeatable Read를 기본으로 사용한다. 이를 고려하여 적절한 격리 수준을 사용해야한다.

 

 

728x90