데이터베이스

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

위시리 2025. 2. 20. 13:38
트랜잭션이란?

https://wishlee0204.tistory.com/259

데이터베이스의 상태가 변하는 과정에서 일관성과 무결성을 유지하기 위해 실행되는 연산들의 집합

데이터베이스에서 여러 연산(쿼리)이 수행될 때, 일부만 실행되고 중간에 실패하면 데이터 정합성이 깨질 위험이 있다.
따라서 이를 방지하기 위해 트랜잭션을 사용하여 데이터의 정합성을 보장할 수 있다.

 

 

트랜잭션 격리 수준이란?

트랜잭션 격리 수준은 여러 트랜잭션이 동시에 실행될 때 서로 간섭하지 않도록 정해진 규칙이다.

즉, 실행 중인 트랜잭션의 중간 결과(DB를 수정하기 위해 쿼리가 실행되는 동안)에
다른 트랜잭션이 해당 데이터에 접근/변경/조회/수정할 수 있는 정도를
조정하는 격리 레벨(수준)을 설정하는 것을 의미한다.

이때 격리 수준이 낮을 수록 여러 트랜잭션이 동시에 같은 데이터를 수정할 수 있어 성능이 향상될 수 있지만, 데이터 정합성이 저하될 가능성이 있다.
반대로, 격리 수준이 높을 수록 트랜잭션이 완전히 독립적으로 실행되도록 하여 데이터 정합성이 보장되지만, 동시 처리 성능(Concurrency)이 저하될 수 있다.

트랜잭션 격리 수준은 SQL 표준(ANSI / ISO)에서 정의한 4가지 수준이 있으며,
DBMS별로 기본 설정 및 동작 방식이 다를 수 있다.

 

 

트랜잭션 격리 수준은 왜 필요할까?
  1. 트랜잭션의 독립성 (ACID의 Isolation)을 보장해야 한다.
    • 여러 트랜잭션이 동시에 수행될 때, 잘못된 데이터 읽기(Dirty Read, Non-Repeatable Read, Phantom Read) 문제가 발생할 수 있다.
    • 따라서 격리 수준을 통해 허용할 수 있는 동시성 문제의 범위를 정해야 한다.
  2. Locking을 통한 완전한 순차 실행은 성능 저하를 초래할 수 있다.
    • 모든 트랜잭션을 순차적으로 실행하면 동시성을 포기하는 것이므로 DB 성능이 크게 떨어진다.
    • 따라서 락을 최소화하거나, MVCC 같은 동시성 제어 기법을 활용해야 한다.
  3. 성능과 데이터 정합성 사이의 균형을 맞춰야 한다.
    • Locking을 줄이면 성능은 좋아지지만, 데이터 정합성이 깨질 위험이 증가한다.
    • Locking을 늘리면 데이터 정합성은 높아지지만 성능이 저하된다.
    • 따라서 격리 수준을 조절하면서 적절한 수준의 동시성과 정합성을 유지해야 한다.

 

 

트랜잭션과 locking


잠금(Lock)과 트랜잭션은 서로 비슷한 개념 같지만
잠금은 동시성을 제어하기 위한 기능이고
트랜잭션은 데이터의 정합성을 보장하기 위한 기능이다.

  • 잠금 (Lock)
    : 여러 커넥션에서 동시에 동일한 자원을 요청할 경우 순서대로 한 시점에서는 하나의 커넥션만 변경할 수 있게 해주는 역할
    • 자원 : 레코드나 테이블을 의미
  • 트랜잭션 (Transaction)
    • 꼭 여러 개의 변경 작업을 수행하는 쿼리가 조합되었을 때만 의미있는 개념은 아니다.
    • 하나의 논리적인 작업 셋 중 쿼리가 하나이든, 두 개 이상이든 상관 없이 논리적인 작업 셋 자체가 100% 적용되거나 아무 것도 적용되지 않아야 함을 보장하는 것이다.
    • ex. HW 에러 또는 SW 에러와 같은 문제로 인해 작업에 실패가 있을 경우, 특별한 대책이 필요하게 되는데 이러한 문제를 해결하는 것

정합성을 보장하기 위해 동시성을 처리해야 하고, 동시성을 제어하는 방법 중 하나로 Locking이 존재하지만,
locking이 유일한 방법은 아니다!

Locking은 트랜잭션 간의 충돌 방지를 위해 데이터 정합성을 유지하는 대표적인 방법
→ MVCC 같은 다른 동시성 제어 기법도 존재한다.

 

 

트랜잭션이 그렇게 지키고 싶어하는 정합성이란?

데이터 정합성은 정확하고, 일관되며, 신뢰할 수 있는 데이터 상태를 의미한다.
데이터가 변경되거나 처리될 때 데이터베이스의 규칙을 위반하지 않고 유지되는지를 보장하는지에 대한 개념이다.

트랜잭션을 통해 ACID 속성을 보장하여 데이터 정합성을 유지할 수 있다.
실무에서는 트랜잭션 격리 수준, 무결성 제약 조건, 백업 및 로그 등을 활용하여 정합성을 유지한다.

 

📌 데이터 정합성의 주요 개념

 

1. 무결성(Integrity)

  • 데이터가 정해진 규칙과 제약 조건을 만족해야 한다.
  • 예: NOT NULL, UNIQUE, FOREIGN KEY, CHECK 제약 조건

2. 일관성(Consistency)

  • 데이터가 변경된 후에도 데이터베이스의 규칙을 준수하며 논리적인 모순이 없어야 한다.
  • 예: 계좌 이체 시, 송금자의 계좌에서 돈이 빠져나가면 수신자의 계좌에 동일한 금액이 증가해야 한다.

3. 정확성(Accuracy)

  • 데이터가 정확하게 입력되고, 잘못된 값이 저장되지 않도록 보장해야 한다.
  • 예: 나이 필드에 -10 같은 값이 입력되지 않도록 한다.

4. 신뢰성(Reliability)

  • 장애 발생 시에도 데이터가 손상되지 않고 신뢰할 수 있어야 함
  • 예: 트랜잭션 로그를 이용한 장애 복구

 

 

트랜잭션을 다룰 때 발생할 수 있는 문제점들 (낮은 격리 수준을 활용할 때 발생하는 현상)

동시에 두 개 이상의 트랜잭션이 실행되는데, 한 트랜잭션이 끝나기 전(commit 되기 전)에 데이터의 무결성이 깨지는 문제
즉, 트랜잭션의 고립(격리) 수준이 낮으면 데이터 무결성이 깨질 가능성이 높아진다.


 1. 더티 리드(Dirty Read)

  • 다른 트랜잭션이 커밋되지 않은 변경 사항을 읽는 현상
  • 트랜잭션 A가 변경한 데이터를 트랜잭션 B가 커밋 전에 읽으면 데이터 정합성이 깨질 수 있다.
  • 예: A가 돈을 송금했지만 트랜잭션이 롤백되었을 때, B가 A의 계좌에서 돈이 빠져나간 것처럼 보이는 경우

  • 커밋되지 않은 수정 중인 데이터를 다른 트랜잭션에서 읽을 수 있도록 허용할 때 발생하는 현상
  • 어떤 트랜잭션에서 아직 실행이 끝나지 않은 다른 트랜잭션에 의한 변경사항을 보게되는 경우

발생 Level: Read Uncommitted

 2. Non-Repeatable Read (비반복 가능 읽기)

  • 같은 데이터를 두 번 읽을 때 값이 변경되는 현상
    (데이터를 2번 읽는 트랜잭션이 끝나기 전(commit 되기 전)에 즉, 한 트랜잭션에서 값을 2번 일었는데 값이 달라지는 현상)
  • 두 개의 트랜잭션이 동일한 데이터를 수정할 경우 데이터 충돌이 발생
  • 예: 한 트랜잭션에서 특정 고객의 잔액을 조회했는데, 다른 트랜잭션이 잔액을 변경하면 첫 번째 조회 결과와 다르게 나옴
  • 해결 방법: 트랜잭션 격리 수준 조정 (Repeatable Read 이상)

  • 한 트랜잭션에서 같은 쿼리를 두 번 수행할 때 그 사이에 다른 트랜잭션 값을 수정 또는 삭제하면서 두 쿼리의 결과가 상이하게 나타나는 일관성이 깨진 현상

 발생 Level: Read Committed, Read Uncommitted

 3. Phantom Read (팬텀 리드)

  • 한 트랜잭션이 특정 조건을 만족하는 행을 조회했는데, 이후 다른 트랜잭션이 행을 추가하거나 삭제하여 결과가 달라지는 현상
  • 예: SELECT COUNT(*) FROM users WHERE age > 30; 이후 다른 트랜잭션이 31세 사용자를 추가하면 결과가 달라짐

  • 한 트랜잭션 안에서 일정 범위의 레코드를 두 번 이상 읽었을 때, 첫번째 쿼리에서 없던 레코드가 두번째 쿼리에서 나타나는 현상
  • 트랜잭션 도중 새로운 레코드 삽입을 허용하기 때문에 나타나는 현상임

→ 발생 Level: Repeatable Read, Read Committed, Read Uncommitted

❌ 4. 무결성 제약 조건 위반

  • 예: FOREIGN KEY가 설정된 테이블에서 부모 데이터 없이 자식 데이터를 추가

 

✅ 데이터 정합성을 보장하는 방법

  1.  트랜잭션 사용 (COMMIT / ROLLBACK)
  2. 적절한 트랜잭션 격리 수준 적용 (Read Committed, Serializable 등)
  3. 무결성 제약 조건 적용 (NOT NULL, UNIQUE, FOREIGN KEY) 
  4. 정합성 체크 로직 구현 (CHECK, 애플리케이션 단에서 검증)
  5. 트랜잭션 로그 및 백업 활용 (장애 발생 시 데이터 복구)

 

 

트랜잭션을 다룰 때 발생하는 문제들을 해결하고자 격리 수준을 설정하였다.

Isolation level 종류


🔹
1.  Read Uncommitted ( lv. 0 )

select 문장이 수행되는 동안 해당 데이터에 Shared Lock이 걸리지 않는 계층

  • 트랜잭션에 처리 중이거나, 아직 commit 되지 않는 데이터를 다른 트랜잭션이 읽는 것을 허용
  • commit 하지 않은 데이터 조차도 접근할 수 있는 격리 수준
사용자1이 A라는 데이터를 B라는 데이터로 변경하는 동안 사용자2는 아직 완료되지 않은(Uncommitted) 트랜잭션이지만 데이터B를 읽을 수 있다.

그러나 정합성의 문제로 권장하지 않는다.
데이터 베이스의 일관성을 유지하는 것이 불가능하다.

🚨 발생 가능 문제점

  • Dirty Read
  • Non-Repeatable Read
  • Phantom Read

 

🔹 2.  Read Committed ( lv. 1 )

select 문장이 수행되는 동안 해당 데이터에 Shared Lock이 걸리는 계층

  • 트랜잭션이 수행되는 동안 다른 트랜잭션이 접근할 수 없어 대기해야 한다.
  • 트랜잭션이 커밋되어 확정된 데이터만 다른 트랜잭션이 읽도록 허용한다.

  • 커밋되지 않은 데이터에 대해서는 실제 DB 데이터가 아닌 undo 로그에 있는 이전 데이터를 가져온다.
  • 오라클의 기본 트랜잭션 격리 수준 - 뿐만 아니라 대부분의 SQL 서버가 default로 사용하는 격리 수준
  • Dirty Read의 발생 가능성을 막을 수 있다.
사용자1이 A라는 데이터를 B라는 데이터로 변경하는 동안 사용자2는 해당 데이터에 접근이 불가능하다.


🚨 발생 가능 문제점

  • Non-Repeatable Read
    • Read Committed 격리 수준에서는 한 트랜잭션이 COMMIT된 데이터만 읽을 수 있도록 허용되기 때문
    • 하지만, 한 트랜잭션이 데이터를 다시 조회할 때, 중간에 Commit된 데이터가 반영될 수 있다.
    • 따라서 트랜잭션 중간에 같은 데이터를 여러 번 조회하면 값이 달라지는 문제가 발생할 수 있다.
  • Phantom Read

 

🔹 3.  Repeatable Read ( lv. 2 )

트랜잭션이 완료될 때까지 select 문장이 사용하는 모든 데이터에 shared lock이 걸리는 계층

  • 트랜잭션 범위 내에서 같은 데이터를 여러 번 조회해도 항상 동일한 결과를 보장하는 격리 수준
    즉, 트랜잭션이 시작된 후 같은 데이터를 다시 읽을 때, 중간에 다른 트랜잭션이 해당 데이터를 변경하거나 삭제해도 영향을 받지 않아야 한다.

  • 다른 사용자는 트랜잭션 영역에 해당되는 데이터에 대한 수정 불가능
  • MVCC 를 이용해 한 트랜잭션 내에서 동일한 결과를 보장하지만, 새로운 레코드가 추가되는 경우 부정합 발생 가능

  • MySQL의 InnoDB 엔진의 기본 트랜잭션 격리 수준
  • 어떤 트랜잭션이 읽은 데이터를 다른 트랜잭션이 수정하더라도 동일한 결과를 반환할 것을 보장
    • 트랜잭션 번호를 참고하여 자신보다 먼저 실행된 트랜잭션의 데이터만을 조회
      • 테이블에 자신 이후에 실행된 트랜잭션의 데이터가 존재할 경우 UNDO 로그 참고로 데이터 조회
  • 새로운 레코드의 추가까지는 막지 않음

🚨 발생 가능 문제점

  • Phantom Read
    • Repeatable Read는 동일한 데이터를 여러 번 조회하면 값이 변하지 않도록 보장하지만, 새로운 행이 추가되거나 삭제되는 것 가능하다.
      따라서 다시 조회했을 때 트랜잭션 중간에 새로운 데이터가 삽입되거나 삭제되면 결과가 달라지는 Phantom Read(팬텀 리드) 문제가 발생할 수 있다.

    • BUT MVCC 덕분에 일반적인 MySQL 조회에선 발생하지 않는다.
    • UNDO 로그가 아닌 테이블로부터 데이터를 가져올 때 발생할 수 있으나 해당 케이스는 거의 존재하지 않는다.

 

  • Dirty Read 방지 → Commit되지 않은 데이터를 읽을 수 없다.
  • Non-Repeatable Read 방지 → 트랜잭션이 진행되는 동안 같은 데이터를 읽으면 항상 같은 값이 유지된다.

 

왜 Repeatable Read에서 MVCC를 이용할까?

MVCC 란? (다중 버전 동시성 제어)

  • 동시 접근을 허용하는 DB에서 동시성을 제어하기 위해 사용하는 방법 중 하나
  • 동일한 레코드에 대해 여러 버전의 데이터가 존재하는 것
    • 일반적인 DBMS에서는 변경 전 레코드를 UNDO 영역에 백업해두어 변경 전, 후 데이터가 모두 존재
  • 트랜잭션이 롤백된 경우 데이터 복원이 가능하다.
  • 서로 다른 트랜잭션 간 접근할 수 있는 데이터를 세밀하게 제어한다.
  • 트랜잭션 번호
    • 각 트랜잭션은 순차 증가하는 고유한 트랜잭션 번호가 존재한다.
    • 백업 레코드에 어느 트랜잭션에 의해 백업되었는지 트랜잭션 번호를 함께 저장한다.

 

MySQL에서 Repeatable Read를 기본 격리 수준으로 사용하는 이유는?

  • 격리 수준과 서버 처리 성능
    • serializable이 아니라면 격리 수준이 높다고 MySQL 서버 처리 성능 개선 및 저하가 크게 발생하지 않는다.
    • 결국 UNDO 로그를 통해 레코드를 참조하는 과정이 거의 동일하기 때문이다.
  • Repeatable Read
    • Read Committed 보다 동시 처리 성능이 뛰어나다.
    • 갭 락을 통해 Phantom Read까지 거의 발생하지 않는다.

 

🔹 4.  Serializable ( lv. 3 )

트랜잭션이 완료될 때까지 select 문장이 사용하는 모든 데이터에 shared lock이 걸리는 계층

  • 트랜잭션을 순차적으로 실행
  • 완벽한 읽기 일관성 모드를 제공
  • 다른 사용자는 트랜잭션 영역에 해당하는 데이터에 대한 수정 및 입력이 불가능
  • 가장 엄격한 수준의 격리 수준

  • 어떠한 데이터 부정합 문제도 발생하지 않는다.
    여러 트랜잭션이 동일한 레코드에 동시에 접근할 수 없다.
  • 매우 낮은 동시 처리 성능
    트랜잭션이 순차적으로 처리되어야 한다.

가장 안전하지만, 가장 성능이 떨어지므로 극단적으로 안전한 작업이 필요한 경우가 아니면 사용하지 않는다.

순수한 select 작업에서도 대상 레코드에 넥스트 키 락을 읽기 잠금(shared lock)으로 건다.

 

 

격리 수준 선택 시 고려사항

Isolation Level 대한 조정은 동시성 데이터 무결성 연관되어 있다.
동시성을 증가시키면 데이터 무결성에 문제가 발생하고, 데이터 무결성을 유지하면 동시성이 떨어진다.
또한 레벨을 높게 조정할 수록 발생하는 비용이 증가한다.

 

 

reference

https://github.com/gyoogle/tech-interview-for-developer/blob/master/Computer%20Science/Database/Transaction%20Isolation%20Level.md

 

tech-interview-for-developer/Computer Science/Database/Transaction Isolation Level.md at master · gyoogle/tech-interview-for-de

👶🏻 신입 개발자 전공 지식 & 기술 면접 백과사전 📖. Contribute to gyoogle/tech-interview-for-developer development by creating an account on GitHub.

github.com

https://github.com/JaeYeopHan/Interview_Question_for_Beginner/tree/main/Database#transaction

 

Interview_Question_for_Beginner/Database at main · JaeYeopHan/Interview_Question_for_Beginner

:boy: :girl: Technical-Interview guidelines written for those who started studying programming. I wish you all the best. :space_invader: - JaeYeopHan/Interview_Question_for_Beginner

github.com

https://github.com/jmxx219/CS-Study/blob/main/database/%ED%8A%B8%EB%9E%9C%EC%9E%AD%EC%85%98%EC%9D%98%20%EA%B2%A9%EB%A6%AC%EC%84%B1.md

 

CS-Study/database/트랜잭션의 격리성.md at main · jmxx219/CS-Study

Computer Science && Tech Interview . Contribute to jmxx219/CS-Study development by creating an account on GitHub.

github.com