REPEATABLE READ란?
- REAPEATABLE READ는 MySQL의 InnoDB 스토리지 엔진에서 기본으로 사용되는 격리 수준
- MVCC를 위해 언두 영역에 백업된 이전 데이터를 이용해 동일 트랜잭션 내에서는 동일한 결과를 보여줄 수 있게 보장함
1. 주요 특징
특징설명
동일 쿼리 반복 시 결과 일관성 유지 | 트랜잭션이 시작된 순간의 스냅샷을 기준으로 데이터를 조회한다. |
Phantom Read 방지 | MySQL(InnoDB)은 Next-Key Locking을 통해 팬텀 리드를 막는다. |
Serializable보다 성능이 좋음 | 완벽한 직렬화(Serializable) 수준보다 성능이 높고 동시성도 괜찮은 편이다. |
Read Committed보다 보수적 | 다른 트랜잭션에서 커밋한 내용도, 트랜잭션 내에서는 보이지 않음. |
2. 내부 동작 방식
1. 스냅샷 기반 읽기 (MVCC)
- 트랜잭션이 시작되면 해당 시점의 데이터 스냅샷을 생성하고 이를 기준으로 읽기 작업을 수행함.
- 이후 다른 트랜잭션에서 변경된 데이터가 커밋되더라도, 현재 트랜잭션에는 보이지 않음.
2. Next-Key Lock
- InnoDB에서는 팬텀 리드를 방지하기 위해 기존 행 + 범위에 잠금을 건다.
- 예: SELECT * FROM users WHERE age > 30 FOR UPDATE → age 30~∞ 범위 전체를 잠금.
3. 예시 시나리오
상황
- 트랜잭션 A와 트랜잭션 B가 동시에 실행 중
- 테이블: accounts(id, balance)
Step-
-- 트랜잭션 A 시작
START TRANSACTION;
-- A: 사용자 잔고 확인
SELECT balance FROM accounts WHERE id = 1;
-- 결과: 1000원
-- 트랜잭션 B 시작
START TRANSACTION;
-- B: 사용자 잔고 차감
UPDATE accounts SET balance = balance - 500 WHERE id = 1; COMMIT;
-- 다시 트랜잭션 A에서 같은 쿼리 실행
SELECT balance FROM accounts WHERE id = 1;
-- 결과: 여전히 1000원 (트랜잭션 A가 시작된 시점 기준으로 읽음)
-- 트랜잭션 A 커밋 COMMIT;
4. 예외 상황
사용자 B의 트랜잭션 안에서 SELECT ... FOR UPDATE로 특정 범위의 데이터를 조회한 후, 사용자 A가 그 범위에 해당하는 새로운 데이터를 INSERT하고 COMMIT하면, 사용자 B가 나중에 동일한 SELECT ... FOR UPDATE 쿼리를 다시 실행했을 때 이전에는 없던 유령 데이터가 나타나는 팬텀 리드가 발생할 수 있다. 그 이유는 SELECT ... FOR UPDATE는 일반 SELECT처럼 트랜잭션 시작 시점의 스냅샷(언두 로그)을 참조하는 것이 아니라, 항상 가장 최신 버전의 실제 데이터를 읽어오기 때문이다.
'CS' 카테고리의 다른 글
도메인 주도 설계 정리 - ENTITY, VALUE OBJECT (1) | 2025.06.26 |
---|---|
RealMySQL - 인덱스 스캔 방향 (0) | 2025.06.22 |
Spring 테스트에서 @Transactional과 비관적 락 사용 시 주의점 (2) | 2024.10.14 |
스프링부트 JPA 모범 사례 - @ManyToMany 연관관계를 효과적으로 구성하는 방법 (0) | 2024.08.23 |
[JAVA] String.valueOf()와 toString()의 차이에 대해서 알아보자 feat. Effective Java (0) | 2024.06.07 |