본문 바로가기

👩‍💻 BackEnd/📊데이터베이스 [Database]

트랜잭션 격리 수준(Isolation Levels)

트랜잭션 격리 수준이란?

: 동시에 여러 트랜잭션이 처리될 때, 트랜잭션끼리 얼마나 서로 고립되어있는지를 나타내는 것

즉, 특정 트랜잭션(a)이 다른 트랜잭션(b)에서 변경한 데이터를 볼 수 있도록 허용할지 말지를 결정하는 것이다.


트랜잭션 격리 수준의 종류

  1. READ UNCOMMITTED :
    1. 어떤 트랜잭션의 변경 내용이 Commit, rollback 에 상관없이 다른 트랜잭션에서 보여짐.
    2. 문제점 : 데이터 정합성 문제가 발생할 수 있음.
    3. 예시 :
    A트랜잭션에서 이름을 MOUSE에서  MINI로 변경한다.
    아직 커밋을 하지 않음.
    B트랜잭션에서 MOUSE의 이름을 조회함.
    아직 커밋을 하지 않았음에도 불구하고 MINI로 조회가 됨. -> 이를 DIRTY READ라고 함.
    만약, A트랜잭션에서 문제가 발생해서 커밋을 하지 못하고 롤백을 함.
    B트랜잭션에서는 변경된 이름인 MINI로 조회가 된 뒤 로직이 수행이된다.

따라서 RDBMS 표준에서는 격리수준으로 인정하지도 않는다.

  1. READ COMMITTED :
    • 트랜잭션이 데이터를 읽을 때, 항상 다른 트랜잭션이 커밋한 최신 값을 참조
    • 같은 데이터를 두 번 읽으면 다른 트랜잭션의 커밋에 의해 값이 달라질 수 있음 → 비반복 읽기(Non-Repeatable Read) 발생.
    • 어떤 트랜잭션의 변경내용이 commit 되어야만 다른 트랜잭션에서 조회할 수 있다.
    • 오라클 DBMS 에서 기본으로 사용하고 있고, 온라인 서비스에서 가장 많이 선택되는 격리수준임.
    • non-repeatable read(비반복 읽기문제) 부정합 문제가 발생
      • non-repeatable read(비반복 읽기문제) 문제란?
        • 동일 트랜잭션 내에서 같은 데이터를 두 번 조회할때, 다른 트랜잭션의 commit 으로인해 값이 달라지는 상황
      • 예시 :
      • 트랜잭션 a 에서 특정 데이터를 조회한 결과 ->  100 
        트랜잭션 b 가 그 데이터를 200으로 업데이트 후 커밋. 
        트랜잭션 a 가 다시 조회 시, 값이 200으로 변경됨.
  2. REPEATABLE READ
    • 트랜잭션 시작 시점의 데이터 상태(스냅샷)를 기준으로 값을 보여줌.
      • 트랜잭션 내에서는 동일한 데이터를 여러번 조회해도 항상 동일한 값을 보여줌.
      • 다른 트랜잭션에서 값을 변경하더라도, 해당 변경은 트랜잭션 a 가 종료 될때까지 반영되지 않음. → non-repeatable read 문제는 방지
    • 하지만, 범위조회(예: 특정 조건을 만족하는 데이터 집합 조회)의 경우에는 다른 트랜잭션이 데이터를 추가하거나 삭제하면 그 변경사항이 보일 수 있음 → 팬텀 리드(Phantom Read)가 발생.
    • MySQL DBMS 에서 기본으로 사용하고 있고, 이 격리수준에서는 non-repeatable read(비반복 읽기문제) 부정합 문제가 발생하지 않음.
    • Phantom Read 문제란?
      1. 트랜잭션이 특정 조건에 맞는 데이터를 조회한 후, 같은 조건으로 다시 조회했을 때, 다른 트랜잭션에서 추가되거나 삭제된 데이터가 포함되거나 제외되어 조회되는 현상
      트랜잭션 a가 특정 조건의 데이터를 조회함. 
      트랜잭션 b가 해당 조건에 맞는 새로운 데이터를 삽입하고 커밋함.
      트랜잭션 a가 동일한 조건으로 데이터를 다시 조회하면 추가된 데이터가 나타남.
    이를 방지하기 위해서는 격리 수준을 SERIALIZABLE 로 올리거나,
  3. 범위잠금(Pessimistic Locking)을 사용해야한다.
  1. SERIALIZABLE
    • 가장 높은 격리 수준으로, 모든 트랜잭션을 순차적으로 처리하며, 팬텀리드 문제까지 방지할 수 있다. 다만, 성능 비용이 매우 큼.
    • 예시 :
    • 데이터 읽기과 쓰기 작업이 동시에 발생할때, 다른 트랜잭션은 대기 상태에 들어가고 순차적으로 처리됨.

1~4 까지 내려갈수록 트랜잭션 간의 고립정도가 높이지며, 성능이 떨어지는 것이 일반적이다.

일반적인 온라인 서비스에서는 아래의 두가지 중 하나를 사용한다고 한다.

  1. READ COMMITTED
  2. REPEATABLE READ

MySQL 과 Oracle 에서 기본적으로 사용하는 격리 수준

  • MySQL (REPEATABLE READ) : 기본적으로 더 높은 데이터 정합성을 제공하며, 팬텀리드를 방지하기 위해 InnoDB의 MVCC(다중 버전 동시성 제어)를 활용한다.
  • Oracle (READ COMMITTED) : 팬텀리드 방지는 트랜잭션 설계나 잠김기법을 통해 처리할 수 있도록 유연성을 제공한다.

격리 수준 선택 어떻게 할까?

  • 고성능이 필요한 실시간 서비스 : READ COMMITTED 권장
  • 데이터 정합성이 중요한 서비스 : SERIALIZABLE 권장