트랜잭션 격리 수준: 무결성과 동시성을 조율하는 기준
트랜잭션 격리 수준별 Dirty Read, Non-Repeatable Read, Phantom Read와 DBMS 구현 특성을 실무 관점에서 정리한다.
2026-08-14 · 최초 발행 2025-08-10
동시에 실행되는 트랜잭션의 경계를 정하는 설정
트랜잭션 격리 수준은 여러 사용자가 같은 데이터베이스를 함께 사용할 때, 일관성과 동시성 사이의 균형을 조정하는 장치다. 동시 실행되는 트랜잭션이 서로의 작업을 어느 범위까지 볼 수 있는지를 정해 데이터 불일치를 제어한다.
이는 ACID의 격리성을 뒷받침하는 요소이며, SQL-92는 격리 수준을 4단계로 정의한다. 구현에는 주로 로킹(Locking)이 쓰이지만 DBMS에 따라 MVCC 같은 방식도 함께 활용된다.
일반적으로 격리 수준을 높이면 데이터 일관성은 좋아지는 반면 동시성과 성능에는 부담이 생긴다. 반대로 낮은 수준은 처리 성능과 동시성에 유리할 수 있지만, 읽은 데이터의 신뢰 범위는 좁아진다.
읽기 결과가 흔들리는 방식
아직 확정되지 않은 값을 읽는 Dirty Read
트랜잭션 A가 값을 바꿨지만 커밋하지 않은 상태에서 트랜잭션 B가 그 값을 읽는 경우다. 이후 A가 롤백하면 B는 유효하지 않은 값을 사용하게 된다.
같은 행을 다시 읽었을 때 값이 바뀌는 Non-Repeatable Read
트랜잭션 A가 데이터를 읽은 뒤, 트랜잭션 B가 해당 데이터를 변경하고 커밋한다. A가 같은 데이터를 다시 조회하면 처음과 다른 값을 받는다.
조건 검색의 결과셋이 달라지는 Phantom Read
트랜잭션 A가 조건에 맞는 데이터를 조회한 다음, 트랜잭션 B가 그 조건에 해당하는 행을 삽입하거나 삭제하고 커밋할 수 있다. A가 같은 조건으로 다시 검색하면 결과셋 자체가 달라진다.
격리 강도에 따라 달라지는 읽기 보장
Read Uncommitted: 커밋 전 데이터까지 허용
가장 낮은 격리 수준이다. 트랜잭션 사이의 격리를 제공하지 않으므로, 다른 트랜잭션이 변경했지만 아직 커밋하지 않은 데이터도 읽을 수 있다. Dirty Read, Non-Repeatable Read, Phantom Read가 모두 발생할 수 있다.
동시성과 성능은 가장 높지만 데이터 일관성은 거의 보장되지 않는다. 실시간 모니터링이나 대량 데이터 초기 로딩처럼 정확성보다 성능이 우선인 경우에 사용할 수 있다.
-- 예시: PostgreSQL에서 설정
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
Read Committed: 확정된 데이터만 읽기
트랜잭션은 커밋된 데이터만 읽는다. Dirty Read는 막을 수 있지만 Non-Repeatable Read와 Phantom Read는 여전히 발생할 수 있다.
비교적 좋은 동시성을 유지하면서 커밋 전 데이터 노출을 피할 수 있어 일반적인 웹 애플리케이션과 OLTP 시스템에 쓰인다. 다만 트랜잭션 안에서 같은 쿼리를 반복 실행해도 같은 결과를 보장하지는 않는다.
-- 예시: Oracle에서 설정
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
Repeatable Read: 트랜잭션 안에서 일관된 조회
같은 트랜잭션에서 같은 조회 쿼리를 수행할 때 동일한 결과를 보장하는 수준이다. 트랜잭션 시작 시점의 스냅샷을 기준으로 데이터를 읽으며, Dirty Read와 Non-Repeatable Read를 방지한다. Phantom Read는 여전히 발생할 수 있다.
로킹 기반 구현에서는 SELECT 조건에 맞는 실제 존재 레코드에 공유 락(Shared Lock)을 설정한다. MVCC 기반 구현에서는 트랜잭션이 시작된 시점의 데이터 스냅샷을 유지한다.
트랜잭션 내부의 읽기 일관성을 얻는 대신 Level 1보다 동시성이 낮아질 수 있으며, UPDATE가 많은 환경에서는 성능 영향이 커질 수 있다. 복잡한 보고서 생성이나 일관성이 중요한 재무 트랜잭션이 대상이 된다.
-- 예시: MySQL에서 설정
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
Serializable: 순차 실행과 같은 결과
가장 높은 격리 수준으로, 트랜잭션이 순차적으로 실행된 것과 같은 결과를 보장한다. Dirty Read, Non-Repeatable Read, Phantom Read를 모두 방지한다.
구현에는 SELECT 조건 범위 전체를 잠그는 범위 락(Range Lock), 인덱스 레벨에서 새 레코드 삽입을 막는 인덱스 락이 사용될 수 있다. 완전한 격리와 일관성을 제공하는 대신 동시성이 크게 저하되고 교착 상태(Deadlock)가 발생할 가능성도 높아진다.
은행 계좌 이체나 중요한 재고 관리처럼 데이터 무결성이 절대적으로 중요한 작업에 적합하다.
-- 예시: PostgreSQL에서 설정
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
DBMS마다 다른 기본값과 구현 특성
| DBMS | 기본 격리 수준 | 특징 |
|---|---|---|
| Oracle | Read Committed | Serializable 구현 시 MVCC(다중 버전 동시성 제어) 활용 |
| MySQL (InnoDB) | Repeatable Read | Repeatable Read에서도 특정 상황에서 Phantom Read 방지 기능을 제공하며, MVCC와 락 기반 접근을 모두 사용 |
| SQL Server | Read Committed | Snapshot Isolation을 추가로 제공하고, 락 기반 구현과 MVCC를 모두 지원 |
| PostgreSQL | Read Committed | MVCC 기반으로 읽기 작업이 쓰기 작업을 차단하지 않으며, Serializable Snapshot Isolation(SSI) 구현으로 높은 동시성을 제공 |
요구사항에서 격리 수준을 고르는 법
선택은 데이터 일관성 요구, 성능과 응답 시간 요구, 동시 사용자 수에서 시작한다. 이어서 읽기 중심인지 쓰기 중심인지, 트랜잭션이 얼마나 오래 유지되는지, 충돌 가능성이 얼마나 되는지를 함께 살펴야 한다.
높은 격리 수준이 만드는 성능 비용과 낮은 격리 수준에서 감수해야 할 불일치 위험도 비교 대상이다. 수준을 정한 뒤에는 대형 트랜잭션을 작은 단위로 나눠 락 보유 시간을 줄이고, 적절한 인덱스로 팬텀 리드와 락 경합을 줄일 수 있다. 특정 상황에서는 DB 락보다 애플리케이션 레벨 락이 효율적일 수 있으며, 버전 컬럼이나 타임스탬프를 이용한 낙관적 락(Optimistic Locking)으로 충돌을 감지하는 방법도 있다.
대규모 동시 사용자 환경에서는 격리 수준이 시스템 전체 성능에 직접 영향을 준다. 발생 가능한 읽기 현상과 각 수준의 비용을 이해한 뒤, 실제 트랜잭션 특성에 맞춰 테스트와 모니터링을 이어가야 한다.