트랜잭션에 대한 내용은 해당 포스팅에서 확인 > 2025.08.22 - [CS/데이터베이스] - [DB] 트랜잭션(Transaction)
데이터베이스에서 트랜잭션은 고립성(Isolation)을 보장해야 한다.
다시 말해, 여러 트랜잭션이 동시에 실행되더라도 각 트랜잭션의 결과는 독립적으로 유지되어야 한다.
만약 이를 지키지 않고 여러 트랜잭션이 동시에 같은 데이터에 접근하게 되면, 다음과 같은 문제가 발생할 수 있다.
동시성 문제(이상 현상)
Dirty Read
다른 트랜잭션이 커밋하지 않은 트랜잭션의 중간 값을 읽어 오는 문제이다.
예를 들어, 트랜잭션 A와 트랜잭션 B를 동시에 실행했다고 가정하자.
- 트랜잭션 A는 몇몇의 데이터를 update를 수행하였다.
- 트랜잭션 B는 update한 데이터를 조회하였다.
- 트랜잭션 A는 커밋을 완료하지 않고 Rollback을 수행했다.
⇒ 결국 트랜잭션 B는 조회한 값은 존재하지 않는 값이 된다.
Non Repeatable Read
하나의 트랜잭션에서 동일한 select 쿼리에 대해 다른 값이 조회되는 문제이다.
예를 들어, 한 트랜잭션 내에 같은 쿼리가 2개 있다고 가정하자.
select name from member where id = 100; -- kim
select name from member where id = 100; -- lee
만약 첫 번째 쿼리를 실행한 후(결과: kim), 다른 트랜잭션이 id가 100인 member의 이름을 kim에서 lee로 바꾼다면
→ 두 번째 쿼리 결과는 첫 번째 쿼리와 같음에도 불구하고 다른 값(결과: lee)이 조회될 것이다.
Phantom Read
하나의 트랜잭션에서 동일한 select 쿼리에 대한 결과가 추가 또는 삭제되는 문제이다.
예를 들어, 한 트랜잭션 내에 같은 쿼리가 2개 있다고 가정하자.
SELECT * FROM orders WHERE amount > 150;
SELECT * FROM orders WHERE amount > 150;
만약 첫 번째 쿼리를 실행한 후(결과: 4건 조회), 다른 트랜잭션이 amount가 150 이상인 order를 새로 추가한다면
→ 두 번째 쿼리 결과는 첫 번째 쿼리와 같음에도 불구하고 행의 수(결과: 5건 조회)가 다르게 조회될 것이다.
⇒ Non Repeatable Read는 값, Phantom Read는 집합 단위로 일관성 문제를 가지고 있다.
고립(격리) 수준(Isolation Level)
위와 같은 이상 현상을 방지하기 위해 트랜잭션에서는 고립 수준(Isolation Level)을 설정할 수 있다.
고립 수준은 4가지로 나뉘어진다.
| Dirty Read | Non Repeatable Read | Phantom Read | |
| READ UNCOMMITED | 발생 가능 | 발생 가능 | 발생 가능 |
| READ COMMITED | 방지 | 발생 가능 | 발생 가능 |
| REPEATABLE READ | 방지 | 방지 | 방지(Inno DB) or 발생 가능 |
| SERIALIZABLE | 방지 | 방지 | 방지 |
이상 현상 방지가 많아질수록 데이터의 일관성은 보장되지만, 동시성이 떨어져 성능이 저하된다.
따라서 속도가 가장 느린 고립 수준은 SERIALIZABLE이다.
각 고립 수준에 대해서 알아보자.
READ UNCOMMITED
트랜잭션이 커밋되지 않은 데이터를 다른 트랜잭션이 읽을 수 있도록 허용한다.
즉, Dirty Read를 허용한다.
READ COMMITED
트랜잭션에서 커밋된 데이터만 다른 트랜잭션이 읽을 수 있도록 허용한다.
Dirty Read는 허용되지만, Non Repeatable Read 문제는 여전히 발생 가능하다.
만약 두 트랜잭션 A, B가 각각 해당 쿼리를 실행했다고 가정해보자.
select name from member where id = 100;
그러면 두 트랜잭션은 똑같이 id가 100인 'kim'이라는 데이터를 가지고 있게될 것이다.
하지만 트랜잭션 A가 이름을 'lee'로 바꾸어 커밋을 한다면,
트랜잭션 B의 이름을 다시 조회했을 때는 기존 값('kim')과는 다른 값('lee')을 가지기 때문에 Non Repeatable Read 문제가 발생한다.
REPEATABLE READ
트랜잭션이 시작되기 전에 커밋된 데이터만 다른 트랜잭션이 읽을 수 있도록 허용한다.
Phantom Read가 기본적으로 방지되지만, 특정 조건에서 Phantom Read 현상이 발생할 수 있다.
먼저 Phantom Read가 방지되는 원리에 대해서 알아보자.
만약 트랜잭션 A가 테이블의 모든 행을 조회하고, 트랜잭션 B가 새로운 행을 INSERT하고 커밋해도
→ 트랜잭션 A가 테이블의 모든 행을 다시 조회했을 때는 새로 INSERT된 행은 보이지 않는다.
❓ Phantom Read는 언제 발생하나요?
❗️ 트랜잭션 내에서 SELECT ... FOR UPDATE 를 실행한 후, gap lock이 걸리지 않는다면
SELECT ... FOR UPDATE를 다시 실행했을 때, INSERT된 행이 보이며 Phantom Read 현상이 발생할 수 있다.
(※ gap lock이 걸리지 않는 경우: 인덱스가 없거나 where에서 동등 조건을 사용할 경우 등)
SERIALIZABLE
다른 트랜잭션의 UPDATE, INSERT, DELETE에 영향을 받지 않는 직렬 수행 방식이다.
가장 성능이 떨어지므로, 거의 사용하지 않는다.
👏
참고
'Computer Science > 데이터베이스' 카테고리의 다른 글
| [DB] 인덱스(Index) (0) | 2025.10.31 |
|---|---|
| [DB] 정규화(Normalization) / 1NF, 2NF, 3NF, BCNF (0) | 2025.10.24 |
| [DB] 공통 테이블 식(CTE) (0) | 2025.09.19 |
| [DB] Union vs Union All (0) | 2025.09.10 |
| [DB] 트랜잭션(Transaction) (2) | 2025.08.22 |