오늘의 나보다 성장한 내일의 나를 위해…
Transaction Isolation Level
트랜잭션 격리 수준에 대해 알기 위해서는 일단 트랜잭션이 무엇인지부터 알아야 한다.
트랜잭션: 데이터베이스의 상태를 변화시키기 위해서 수행하는 작업의 단위를 뜻한다.
데이터베이스의 상태를 변화 시킨다는 것은 아래의 질의어(SQL)를 이용하여 데이터베이스를 접근하는 것을 의미한다.
- SELECT
- INSERT
- DELETE
- UPDATE
트랜잭션의 특징(ACID)
- 원자성(Atomicity)
- 일관성(Consistency)
- 독립성(Isolation)
- 지속성(Durability)
원자성(Atomicity)
- 트랜잭션의 연산은 데이터베이스에 모두 반영되든지 아니면 전혀 반영되지 않아야 한다.
- 트랜잭션 내의 모든 명령은 반드시 완벽히 수행되어야 하며, 모두가 완벽히 수행되지 않고 어느 하나라도 오류가 발생하면 트랜잭션 전부가 취소되어야 한다.
일관성(Consistency)
- 트랜잭션이 그 실행을 성공적으로 완료하면 언제나 일관성 있는 데이터베이스 상태로 변환한다.
- 시스템이 가지고 있는 고정요소는 트랜잭션 수행 전과 트랜잭션 수행 완료 후의 상태가 같아야 한다.
독립성, 격리성(Isolation)
- 둘 이상의 트랜잭션이 동시에 병행 실행되는 경우 어느 하나의 트랜잭션 실행 중에 다른 트랜잭션의 연산이 끼어들 수 없다.
- 수행중인 트랜잭션은 완전히 완료될 때까지 다른 트랜잭션에서 수행 결과를 참조할 수 없다.
영속성, 지속성(Durability)
- 성공적으로 완료된 트랜잭션의 결과는 시스템이 고장나더라도 영구적으로 반영되어야 한다.
Commit 연산과 Rollback 연산
Commit 연산
- Commit 연산은 한 개의 논리적 단위(트랜잭션)에 대한 작업이 성공적으로 끝났고 데이터베이스가 다시 일관된 상태에 있을 때, 이 트랜잭션이 행한 갱신 연산이 완료된 것을 트랜잭션 관리자에게 알려주는 연산이다.
Rollback 연산
- Rollback 연산은 하나의 트랜잭션 처리가 비정상적으로 종료되어 데이터베이스의 일관성을 깨뜨렸을 때, 이 트랜잭션의 일부가 정상적으로 처리되었더라도 트랜잭션의 원자성을 구현하기 위해 이 트랜잭션이 행한 모든 연산을 취소(Undo)하는 연산이다.
- Rollback시에는 해당 트랜잭션을 재시작하거나 폐기한다.
트랜잭션 격리 수준
본론으로 돌아와서 이제 트랜잭션 격리 수준에 대해서 살펴보자.
트랜잭션 격리 수준은 고립도와 성능의 Trade-off를 조절한다.
- READ UNCOMMITED: 다른 트랜잭션 중 커밋되지 않은 데이터를 다른 트랜잭션이 참조할 수 있다.
- READ COMMITED: 커밋이 완료된 데이터만 다른 트랜잭션에서 참조할 수 있다.
- REPEATABLE READ: 트랜잭션 시작 전 COMMIT 된 데이터에만 접근할 수 있다.
- SERIALIZABLE: 트랜잭션에 진입하면 락을 걸어 다른 트랜잭션이 접근하지 못하게 한다. (성능이 매우 떨어짐)

트랜잭션 격리 수준이란 트랜잭션들끼리 얼마나 고립되어있는지(잠금수준)를 나타내는 것이다.
특정 트랜잭션이 다른 트랜잭션에 의해 변경된 데이터를 볼 수 있도록 허용할지 말지를 결정하는 것이다.
격리 수준은 위에 명시된 순서로 내려갈수록 고립도가 높아지나 성능이 떨어지는 게 일반적이다.
트랜잭션 격리 수준이 필요한 이유
트랜잭션 수준 읽기 일관성 (Transaction-Level Read Consistency)을 지키기 위해서이다.(다시 말해 동시성 제어 문제 해결을 위해서이다.)
트랜잭션이 시작된 시점으로부터 일관성 있게 데이터를 읽어 들이는 것을 말한다. 하나의 트랜잭션이 진행되는 동안 다른 트랜잭션에 의해 변경사항이 발생하더라도 이를 무시하고 계속 일관성 있는 데이터를 보여준다. (물론 트랜잭션 자신이 발생한 변경사항은 읽을 수 있다.)
READ UNCOMMITTED (트랜잭션 레벨 0)

이 단계에서는 트랜잭션에서 처리 중인, 아직 커밋되지 않은 데이터를 다른 트랜잭션이 읽는 것을 허용한다.
특징
- Dirty Read, Non-Repeatable Read, Phantom Read 현상이 발생한다.
- 다른 트랜잭션에서 수행한 변경 작업에 의해 레코드가 보였다가 안 보였다가 하는 현상
- 이를 방지하기 위해서는 쓰기 잠금을 걸어야 한다.
아직 커밋되지 않은 다른 트랜잭션의 데이터를 읽는 것을 의미한다.
문제점
데이터 정합성에 문제가 많다. 그렇기에 RDBMS 표준에서는 격리수준으로 인정하지 않는다.
예시
- 트랜잭션 A는 테이블의 데이터를 수정중인 상태이고 아직 COMMIT 전이다.
- 트랜잭션 B는 트랜잭션 A가 수정중인 데이터를 조회한다. (이를 Dirty Read라고 한다.)
- 하지만 트랜잭션 B는 COMMIT 되지 않은 데이터를 가지고 로직을 수행한다. (문제 발생)
READ COMMITTED (트랜잭션 레벨 1)

RDB에서 대부분 기본적으로 사용되고 있는 격리 수준으로 실제 테이블 값을 가져오는 것이 아니라 Undo 영역에 백업된 레코드에서 값을 가져온다.
특징
- Dirty Read가 발생하지 않지만(트랜잭션이 COMMIT되어 확정된 데이터만 읽는 것을 허용한다.) Non-Repeatable Read, Phantom Read 현상은 여전히 발생한다.
- 온라인 서비스에서 가장 많이 선택되는 격리수준이다.
- DB2, SQL Server, Sybase의 경우 읽기, 공유 Lock을 이용하여 구현한다.
- Oracle은 Lock을 사용하지 않고 쿼리시작 시점의 Undo 데이터를 제공한다.
문제점
NON-REPEATBLE READ 부정합 문제가 발생할 수 있다.
READ COMMITED 격리 수준에서 실행되는 SQL 문장의 결과가 무엇인지 정확히 예측하고 있어야 한다.
REPEATABLE READ (트랜잭션 레벨 2)

트랜잭션이 시작되기 전에 COMMIT된 내용에 대해서만 조회할 수 있는 격리수준이다.
- MySQL에서는 트랜잭션마다 트랜잭션 ID를 부여하여 트랜잭션 ID 보다 작은 트랜잭션 번호에서 변경한 것만 읽게 된다.
- 변경되기 전 레코드는 Undo 공간에 백업해 두고 실제 레코드 값을 변경한다.
특징
- Dirty Read와 같은 현상은 발생하지 않지만 Phantom Read 현상은 여전히 발생한다.
문제점
하나의 트랜잭션 실행시간이 길어질수록 Undo에 백업된 레코드가 많아져서 멀티 버전을 관리해야 하는 단점이 있다. (하지만 영향을 미칠정도로 트랜잭션이 오래 지속되는 경우가 없어서 READ COMMITTED와 REPEATABLE READ의 성능 차이는 거의 없다고 한다.)
또한, UPDATE 부정합와 Phantom Read가 발생할 수 있다.
SERIALIZABLE (트랜잭션 레벨 3)
선형 트랜잭션이 특정 테이블을 읽는 경우(SELECT) 공유 잠금(shared lock)을 걸어, 다른 트랜잭션에서 해당 테이블의 데이터를 UPDATE, DELETE, INSERT 작업을 못하도록 막는다.
특징
가장 단순한 격리 수준이지만 가장 엄격한 격리 수준으로 Phantom Read가 발생하지 않는다.
문제점
동시 처리 능력 이 다른 격리수준보다 떨어지고 성능저하가 발생하여 데이터베이스에서 거의 사용되지 않는다.
낮은 단계의 트랜잭션 고립화 수준을 사용할 때 발생하는 세 가지 현상

Dirty Read (Uncommitted Dependency)

- 변경 후 아직 Commit 되지 않은 값 읽고, Rollback 후의 값을 다시 읽어 최종 결과 값이 상이한 현상이다.
- Oracle은 다중 버전 읽기 일관성 모델을 채택하여 lock을 사용하지 않고 Dirty Read를 피해 일관성 있는 데이터 읽기가 가능하게 하였다.
Non-Repeatble Read (Inconsistent Analysis)

한 트랜잭션 내에서 같은 쿼리를 두번 수행할 때, 그 사이에 다른 트랜잭션이 값을 수정 또는 삭제함으로써 두 쿼리가 상이하게 나타나는 비 일관성이 발생하는 것을 말한다.
(다시말해 하나의 트랜잭션 내에서 동일한 SELECT를 수행했을 경우 항상 같은 결과를 반환해야하는 REPEATABLE READ 정합성에 어긋나는 것이다.)
- 트랜잭션B에서 1번 상품의 총 투자액을 조회 => 100만원이 조회됨
- 트랜잭션A에서 1번 상품의 총 투자액을 120만원으로 바꾸고 COMMIT
- 트랜잭션B에서 1번 상품의 총 투자액을 다시 조회 => 120만원이 조회됨 (NON-REPEATABLE READ)