Spring

[JPA] 트랜잭션의 ACID 속성 중 격리성(Isolation)이 보장되지 않을 때

leejunkim 2025. 7. 23. 22:28

WeeklyPaper: 트랜잭션의 ACID 속성 중 격리성(Isolation)이 보장되지 않을 때 발생할 수 있는 문제점들을 설명하고, 이를 해결하기 위한 트랜잭션 격리 수준들을 설명하세요.


격리성 (Isolation)

여러 트랜잭션이 동시에 수행될 때, 각 트랜잭션이 서로 영향을 받지 않도록 분리되어야 한다는 것을 뜻한다.

예를 들면 결제 시스템에서, 두 유저가 동시에 같은 상품을 구매할 때, 격리정을 지키지 못한다면 재고 차감이 꼬인다.

🔖 트랜잭션 A 🔖 트랜잭션 B
계좌 잔액: 1000원  
-100원 차감 (900원)  
아직 COMMIT 안 함  
  A의 잔액 조회 → 900원 (Dirty Read 발생)
  900원을 기준으로 로직 수행
A: ROLLBACK  
잔액은 1000원으로 복구  

 

  • 실무에서는 비즈니스 요구에 따라 적절한 격리 수준을 선택해야 하고, 높은 격리성일수록 성능 저하를 고려해야한다.

 

격리성을 지키지 못할 시 발생하는 문제점

  • 더티 리드 (Dirty Read)
    • 아직 커밋(Commit)되지 않은 다른 트랜잭션의 수정 사항을 읽는 문제.
    • 해당 트랜잭션이 롤백(Rollback)될 경우, 다른 트랜잭션은 더 이상 유효하지 않은, 즉 '더러운' 데이터를 읽고 작업을 수행하게 되어 데이터 불일치를 유발gksek
    • (위의 예시)
  • 반복 불가능한 읽기 (Non-Repeatable Read)
    • 한 트랜잭션 내에서 동일한 쿼리를 두 번 이상 실행했을 때, 그 사이에 다른 트랜잭션이 값을 수정하고 커밋하면 결과가 다르게 나타나는 문제.
    • 이로 인해 트랜잭션이 진행되는 동안 데이터의 일관성을 신뢰할 수 없게 된다.
  • 유령 읽기 (Phantom Read)
    • 한 트랜잭션 내에서 특정 범위의 데이터를 조회했는데, 그 사이에 다른 트랜잭션이 새로운 레코드를 삽입하거나 삭제하고 커밋해서 이전 조회에서는 보이지 않던 레코드(유령)가 나타나는 문제.
    • 주로 데이터의 집계나 범위 기반의 작업에서 논리적 오류를 발생시킬 수 있다.

 

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

위의 문제들을 해결하기 위해 표준 SQL은 아래와 같은 네 가지 트랜잭션 격리 수준을 정의한다.

아래로 갈수록 격리 수준이 높아지지만, 동시 처리 성능은 저하될 수 있다.

  1. Read Uncommitted (레벨 0)
    • 설명: 가장 낮은 격리 수준으로, 다른 트랜잭션이 커밋하지 않은 데이터를 읽는 것을 허용함.
    • 해결하는 문제: 없음
    • 발생 가능한 문제: 더티 리드, 반복 불가능한 읽기, 유령 읽기
  2. Read Committed (레벨 1)
    • 설명: 대부분의 상용 데이터베이스에서 기본값으로 사용하는 격리 수준. 트랜잭션은 커밋된 데이터만 읽을 수 있다.
    • 해결하는 문제: 더티 리드
    • 발생 가능한 문제: 반복 불가능한 읽기, 유령 읽기
  3. Repeatable Read (레벨 2)
    • 설명: 트랜잭션이 시작될 때의 데이터 버전을 생성하고, 트랜잭션이 끝날 때까지 동일한 데이터를 일관되게 읽을 수 있도록 보장한다.
    • 해결하는 문제: 더티 리드, 반복 불가능한 읽기
    • 발생 가능한 문제: 유령 읽기 (새로운 레코드 추가는 막지 못할 수 있음)
  4. Serializable (레벨 3)
    • 설명: 가장 엄격한 격리 수준 -> 트랜잭션을 순차적으로 실행하는 것과 같은 결과를 보장한다. 읽기 작업에도 공유 잠금(Shared Lock)을 설정하여 다른 트랜잭션이 해당 데이터를 수정하거나 새로운 레코드를 삽입하는 것을 막는다.
    • 해결하는 문제: 더티 리드, 반복 불가능한 읽기, 유령 읽기
    • 특징: 완벽한 데이터 일관성을 제공하지만, 잠금으로 인한 동시 처리 성능 저하가 가장 크다.