트랜잭션과 격리 수준

2025. 8. 8. 14:13·Study/Database

TL;DR

트랜잭션은 작업을 모두 성공하거나 모두 실패시키는 작업 단위이며, ACID 속성으로 무결성을 보장한다.
격리성(Isolation)은 동시에 실행되는 트랜잭션이 서로 간섭하지 않도록 하는 성질로 격리 수준에 따라 정합성과 성능이 달라진다.
MySQL InnoDB는 기본적으로 `Repeatable Read` 를 사용해 대부분의 정합성 문제를 막지만, 경합이 심한 자원은 추가 락이나 더 높은 격리 수준이 필요할 수 있다.

 

 

서론

이번 프로젝트에서 주문 로직을 구현하던 중 멱등성에 대해 고민하다가 예상치 못한 동시성 문제를 마주하게 되었다.

- 사용자가 발급받은 쿠폰은 단 한 번만 사용할 수 있어야한다.
- 재고 차감은 동시에 여러 사용자가 주문하더라도 일관성을 유지해야한다.

애플리케이션 로직으로 최대한 방어하더라도 트래픽이 몰릴 경우 충돌이 발생하거나 잘못된 값이 저장될 가능성은 남아있었기 때문에 좀 더 근본적인 해결책을 찾아보기로 했다.

결국 문제를 해결하려면 트랜잭션과 그 격리 수준, 그리고 데이터베이스가 제공하는 동시성 제어 방식을 제대로 이해할 필요가 있다고 생각했고 그 학습과정을 정리해보고자 한다.

 

 

트랜잭션(Transaction)

트랜잭션은 일반적으로 하나의 작업 단위를 의미한다. 하나의 트랜잭션으로 묶인 작업들은 모두 성공하거나 모두 실패해야 한다.

재고 차감 → 포인트 차감 → 주문내역 저장 이라는 일련의 과정 중 하나라도 실패하면 나머지 단계도 되돌려야 한다는 것이다.

그렇지 않으면 재고는 줄었는데 주문이 실패하거나, 포인트만 차감되는 데이터 불일치가 발생하게 된다.

 

 

ACID

트랜잭션 이야기를 하다 보면 꼭 나오는 개념 중 하나로 ACID가 있다. ACID는 DB에서 트랜잭션의 무결성을 보장하기 위해 꼭 지켜야하는 4가지 원칙이다.

Atomicity 원자성 트랜잭션의 모든 작업은 전부 성공하거나 실패해야함
Consistency 일관성 트랜잭션 전후로 제약 조건과 규칙을 유지해야함
Isolation 격리성 동시에 실행되는 트랜잭션 간 간섭이 없어야함
Durability 지속성 커밋되어 저장된 데이터는 지속적으로 유지되어야함

원자성은 가장 핵심적인 개념으로 All or Nothing 이라고 기억하면 쉽다. 중간에 재고 차감 로직에서 예외가 발생하더라도 포인트가 차감되는 일은 없어야 한다는 것이다. 일관성은 주문 트랜잭션이 완료된 후 재고나 포인트 잔액이 음수가 되지 않고 제약조건과 규칙을 유지하는 것을 의미한다. 격리성은 하나의 쿠폰에 여러 요청이 동시에 접근해도 단 한 번만 사용할 수 있도록 보장하는 개념이다. 마지막으로 지속성은 주문이 완료되어 결과가 저장되면, 서버가 재시작하더라도 그 내역이 계속 유지되는 것을 말한다.

여기서 격리성이 바로 격리 수준의 핵심 키워드이다. 여러 트랜잭션이 동시에 실행될 때 얼마나 간섭을 차단할지, 서로의 변경 내역을 어느 시점에 볼 수 있도록 할지를 결정하는 것이 트랜잭션 격리 수준이다. 이 설정에 따라 데이터의 정합성과 성능이 크게 달라진다.

 

 

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

트랜잭션 격리 수준은 크게 4가지로 나뉜다.

  • Read Uncommitted: 아직 커밋되지 않은 데이터를 읽을 수 있음
  • Read Committed: 커밋된 데이터만 읽을 수 있음
  • Repeatable Read: 같은 트랜잭션 내에서 항상 동일한 조회 결과를 보장함
  • Serializable: 모든 트랜잭션을 순차적으로 실행한 것과 동일하게 동작함

성능은 Read Uncommitted에서 Serializable로 갈수록 낮아진다.

격리 수준이 높을 수록 데이터 일관성은 보장되지만 동시 처리 성능은 떨어진다. 반대로 낮으면 성능은 좋지만 Dirty Read, Non-Repeatable Read, Phantom Read와 같은 문제가 발생할 수 있다.

격리 수준 Dirty Read Non-repeatable Read Phantom Read
Read Uncommitted ✅ 발생 ✅ 발생 ✅ 발생
Read Committed ❌ 방지 ✅ 발생 ✅ 발생
Repeatable Read ❌ 방지 ❌ 방지 ✅ 발생 (MySQL InnoDB는 ❌)
Serializable ❌ 방지 ❌ 방지 ❌ 방지
  • Dirty Read: 다른 트랜잭션에서 커밋하지 않은 데이터를 읽음
  • Non-Repeatable Read: 같은 트랜잭션 내 동일 조건 조회 결과가 달라짐
  • Phantom Read: 같은 조건의 행 수나 집합이 중간에 변경됨
참고로 MySQL InnoDB의 기본 격리 수준은 Repeatable Read 이며 대부분 케이스에서 데이터 정합성을 보장한다. 다만 완전한 동시성 제어가 필요한 대용량 트래픽에서 재고차감, 쿠폰 사용과 같은 시나리오에서는 비관적 락, 낙관적 락 또는 Serializable 수준의 제어를 함께 고려해야 한다.

 

 

마무리

실제로 주문 로직을 구현하면서 동시성 문제를 겪어보니 데이터베이스와 트랜잭션 격리 수준 설정이 데이터 정합성과 성능에 얼마나 큰 영향을 주는지 실감하게 되었다. 설계 단계에서부터 이러한 설정을 충분히 고민하고 반영하는 것이 중요하다는 것을 다시 한번 느꼈다. 특히 내가 사용하는 데이터베이스의 동작 원리를 더 깊이 이해해야겠다는 생각이 들었다.

 

 

참고

Real MySQL 8.0, 김영민, 위키북스, 2021

https://mangkyu.tistory.com/30

https://mangkyu.tistory.com/299

 

반응형

'Study > Database' 카테고리의 다른 글

주문 로직에서 락 적용과 트랜잭션  (4) 2025.08.08
MySQL InnoDB와 트랜잭션  (3) 2025.08.08
'Study/Database' 카테고리의 다른 글
  • 주문 로직에서 락 적용과 트랜잭션
  • MySQL InnoDB와 트랜잭션
haylee
haylee
개발하면서 보고 듣고 느낀 것들을 정리하는중
  • haylee
    haylee
    haylee
    • 홈
    • GitHub
    • LinkedId
    • 분류 전체보기 (19)
      • Project (6)
        • 회고 (6)
      • Study (13)
        • Database (3)
        • Test (1)
        • Architecture (9)
  • hELLO· Designed By정상우.v4.10.1
haylee
트랜잭션과 격리 수준
상단으로

티스토리툴바