MySQL InnoDB와 트랜잭션

2025. 8. 8. 16:49·Study/Database

TL;DR

InnoDB는 MVCC + Undo Log로 스냅샷 읽기를 제공하고, Next-Key Lock으로 신규 레코드 삽입까지 차단하여 Repeatable Read에서도 Phantom Read를 방지한다.

 

 

서론

앞서 트랜잭션과 격리 수준을 살펴보면서 MySQL의 InnoDB의 기본 격리 수준이 Repeatable Read이고, 대부분의 동시성 문제를 방지할 수 있다고 확인했다. 특히 일반적으로 Repeatable Read에서 발생할 수 있는 Phantom Read 현상도 InnoDB에서는 방지된다고 한다. 어떻게 InnoDB는 내부적으로 그런 격리성을 보장하는 걸까? 그리고 다른 DB와는 어떻게 다를까?

 

 

MVCC(Multi Version Concurrency Control)

MySQL 이라고 해서 항상 트랜잭션을 제공하는 것은 아니다. 스토리지 엔진 중 하나인 MyISAM은 트랜잭션을 제공하지 않지만 InnoDB는 MVCC를 이용해 레코드 단위의 트랜잭션을 지원한다.

MVCC (다중 버전 동시성 제어)는 레코드 레벨 트랜잭션을 지원하는 DBMS가 제공하는 기능으로, 스냅샷을 이용해 락을 걸지 않고도 일관적인 읽기를 가능하게 한다. 여기서 멀티 버전이란 하나의 레코드에 여러 버전을 관리한다는 것으로 덕분에 변경 내역이 커밋되기 전까지는 다른 트랜잭션에서 볼 수 없다.

간단히 말하면 읽을 때는 과거 버전을 보고, 쓸 때는 최신 버전을 갱신함으로써 읽기 작업과 쓰기 작업이 서로 방해하지 않도록 한다는 것이다. 덕분에 읽기 작업이 쓰기 작업 종료까지 기다릴 필요가 없어져 동시성을 높아지고 읽기 지연이 줄어든다.

 

 

Undo Log

MVCC에서 스냅샷 역할을 하는 것이 바로 이 Undo Log 이다. InnoDB가 트랜잭션과 격리 수준을 보장하기 위해 변경 전 데이터를 백업해두는 영역이다. InnoDB 에서 Undo Log는 아래와 같이 활용된다.

  • 트랜잭션 보장
  • 트랜잭션 롤백 시 변경된 데이터를 백업해둔 이전 버전의 데이터를 이용해 복구함
  • 격리 수준 보장
  • 특정 커넥션에서 데이터 변경 중 다른 커넥션에서 조회 시 격리 수준에 맞게 백업한 데이터를 반환하기도 함

결과적으로 InnoDB는 스냅샷 읽기를 제공하며 Repeatable Read에서도 같은 트랜잭션 내에서는 항상 동일한 데이터를 읽을 수 있게 보장한다.

 

 

Repeatable Read와 Phantom Read

Repeatable Read는 MVCC를 이용해 한 트랜잭션 내에서 동일한 결과를 보장한다. 트랜잭션 시작 시점의 스냅샷을 기준으로 데이터를 읽기 때문에 다른 트랜잭션이 데이터를 수정하거나 삭제해도 현재 트랜잭션에서는 볼 수 없다. 여기까지는 대부분의 DBMS가 동일하게 동작한다.

하지만 새로운 레코드가 추가되는 경우, Undo Log에 존재하지 않는 데이터이기에 Phantom Read 현상이 발생할 수 있다. Phantom Read는 한 트랜잭션 내에서 같은 조건으로 두 번 조회했는데 두 번째에서는 새로운 행이 보이는 현상을 말한다.

아래와 같은 시나리오가 있다.

  • A가 PRICE >= 10000 조건으로 상품 목록 조회
  • B가 PRICE = 15000 인 상품 추가
  • A가 트랜잭션 종료 전 동일 조건으로 재조회

 

일반적인 DBMS 에서는 Repeatable Read에서도 이런 Phantom Read 가 발생할 수 있다.

sequenceDiagram
    participant A as 트랜잭션 A
    participant DB
    participant B as 트랜잭션 B

    A->>DB: [price>=10000] SELECT
    DB-->>A: 상품1, 상품2

    B->>DB: 상품3 [price=15000] INSERT
    DB-->>B: INSERT 성공

    A->>DB: [price>=10000] SELECT
    DB-->>A: 상품1, 상품2, [상품3]

 

하지만 InnoDB에서는 MVCC + Undo Log 로 스냅샷 읽기를 제공해 데이터 일관성을 보장하고, 추가로 Next-Key Lock (Record Lock + Gap Lock)을 사용해 새로운 행 삽입을 차단해 Phantom Read를 방지한다.

sequenceDiagram
    participant A as 트랜잭션 A
    participant DB
    participant B as 트랜잭션 B

    A->>DB: [price>=10000] SELECT
    DB-->>A: 상품1, 상품2

    B->>DB: 상품3 [price=15000] INSERT
    DB-->>B: gap lock 충돌 → 대기 or 실패

    A->>DB: [price>=10000] SELECT
    DB-->>A: 상품1, 상품2

 

여기서 Next-Key Lock은 InnoDB가 제공하는 스토리지 엔진 수준의 락이다. 이번 글에서는 깊게 다루진 못하고 간단하게만 정리해 보았다.

  • Record Lock
    • 특정 레코드(MySQL에서는 인덱스의 레코드)에 잠금을 걸어 다른 트랜잭션이 해당 레코드를 수정/삭제하지 못하게 함
  • Gap Lock
    • 레코드 자체가 아닌 레코드 사이의 빈 공간(gap)에 잠금을 걸어 새로운 레코드 삽입을 방지
  • Next-Key Lock
    • (Record Lock + Gap Lock) 특정 레코드와 그 앞의 갭까지 함께 잠금
  • Auto Increment Lock
    • AUTO_INCREMENT 컬럼에 순차값을 부여하기 위해 테이블 단위로 거는 락

 

 

마무리

그동안 보편적으로 사용해온 MySQL과 InnoDB의 기능들을 당연하게만 생각하고, 정작 그 기능이 내부적으로 어떻게 구현되는지는 깊게 생각해 본 적이 없었다. 그저 MySQL 기본 격리 수준이 Repeatable Read라서 안전하다더라 정도로만 알고 있던 것이 돌아보니 조금 부끄럽게 여겨졌다.

이번에 공부한 내용이 아주 깊이 있는 수준은 아니지만 그래도 이제는 왜 안전한지, 어떤 내부 메커니즘 때문인지를 설명할 수 있게 되었다. 스토리지 엔진이 제공하는 락에 대해서도 좀 더 깊이 공부해보려고 한다. 앞으로 동시성 설계나 트랜잭션 전략을 세울 때에도 큰 도움이 될 것 같다.

 

 

참고

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

https://mangkyu.tistory.com/298

반응형

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

주문 로직에서 락 적용과 트랜잭션  (4) 2025.08.08
트랜잭션과 격리 수준  (2) 2025.08.08
'Study/Database' 카테고리의 다른 글
  • 주문 로직에서 락 적용과 트랜잭션
  • 트랜잭션과 격리 수준
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
MySQL InnoDB와 트랜잭션
상단으로

티스토리툴바