팬텀 충돌(Phantom Conflict, 팬텀 문제, Phantom Read)은 트랜잭션이 동일한 조건으로 여러 번 조회할 때, 다른 트랜잭션이 중간에 데이터를 삽입하거나 삭제하여 결과가 달라지는 현상을 의미합니다.
이는 반복 가능한 읽기(Repeatable Read) 수준에서도 발생할 수 있는 문제이며, Serializable(직렬화) 수준의 격리성을 적용해야 방지할 수 있습니다.
※ 팬텀 충돌의 내용은 DB를 배운 사람이면 모두 알 수 있는 내용일 텐데 용어가 생소하신 분들이 있을 것 같아 정리해봤습니다. 참고로 정보관리기술사 135회 1교시에 “팬텀 충돌”에 대해 설명하라는 문제가 출제되어 Topic을 따로 정리해봤습니다.
1. 팬텀 충돌(Phantom Read) 예제
📌 예제 상황:
트랜잭션 A
는salary > 5000
인 직원을 조회하고 있음트랜잭션 B
가salary = 6000
인 새 직원을 추가하면,트랜잭션 A
가 다시 같은 조건을 조회할 때 결과가 달라짐
Step 1: 트랜잭션 A가 첫 번째 조회 수행
-- 트랜잭션 A (급여 5000 초과 직원 조회)
BEGIN TRANSACTION;
SELECT * FROM employees WHERE salary > 5000;
결과:
emp_id | name | salary |
---|---|---|
101 | Alice | 6000 |
102 | Bob | 7000 |
Step 2: 트랜잭션 B가 새로운 직원 추가
-- 트랜잭션 B (새로운 직원 추가)
INSERT INTO employees (emp_id, name, salary) VALUES (103, 'Charlie', 6500);
COMMIT;
Step 3: 트랜잭션 A가 같은 조건으로 다시 조회
SELECT * FROM employees WHERE salary > 5000;
변경된 결과:
emp_id | name | salary |
---|---|---|
101 | Alice | 6000 |
102 | Bob | 7000 |
103 | Charlie | 6500 |
🚨 문제 발생:
트랜잭션 A가 같은 조건으로 다시 조회했지만, 이전과 다른 결과가 반환됨 → 팬텀 충돌(Phantom Read) 발생
2. 팬텀 충돌이 발생하는 이유
트랜잭션 A
는 salary > 5000 조건을 만족하는 데이터를 조회트랜잭션 B
가 salary = 6500인 새로운 행을 추가트랜잭션 A
가 다시 조회할 때 처음과 다른 데이터가 존재
이러한 문제는 기존 데이터를 수정(Update)하는 경우가 아니라, 새로운 데이터가 추가(Insert) 또는 삭제(Delete)될 때 발생합니다.
3. 팬텀 충돌 방지 방법
(1) 높은 수준의 트랜잭션 격리 사용 (Serializable)
팬텀 충돌은 Repeatable Read(반복 가능한 읽기) 수준에서도 방지되지 않으며, Serializable(직렬화) 격리 수준에서만 해결됩니다.
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
SELECT * FROM employees WHERE salary > 5000;
✔ Serializable 격리 수준을 사용하면 트랜잭션이 완료될 때까지 다른 트랜잭션이 새로운 데이터를 삽입하지 못하게 함
✔ 성능 저하 위험이 있음 (Lock이 많이 발생함)
(2) 공유 락(Shared Lock) 사용
팬텀 충돌을 방지하려면 테이블에 공유 락(Shared Lock)을 걸어, 다른 트랜잭션이 INSERT, DELETE를 수행하지 못하게 할 수도 있음.
SELECT * FROM employees WHERE salary > 5000 FOR UPDATE;
✔ FOR UPDATE를 사용하면 해당 행이 잠겨, 다른 트랜잭션이 INSERT/DELETE를 하지 못하게 됨.
✔ 단점: 신규 행을 추가하는 것은 막지 못함 → Serializable 수준이 필요할 수 있음.
(3) 갭 락(Gap Lock) 활용 (InnoDB)
MySQL/InnoDB에서는 Gap Lock을 사용하여 팬텀 문제를 방지할 수 있음.
SELECT * FROM employees WHERE salary > 5000 LOCK IN SHARE MODE;
✔ 범위 내에서 새로운 행 추가 방지 (팬텀 Read 차단 가능)
✔ 일부 DBMS에서만 지원됨 (MySQL InnoDB에서 사용 가능)
4. 팬텀 충돌 vs 기타 트랜잭션 충돌 비교
유형 | 설명 | 예제 | 해결 방법 |
---|---|---|---|
Dirty Read (더티 리드) | 커밋되지 않은 데이터를 다른 트랜잭션에서 읽음 | 한 트랜잭션에서 UPDATE 후, 다른 트랜잭션이 변경된 데이터를 읽을 수 있음 | READ COMMITTED 이상 격리 수준 사용 |
Non-Repeatable Read (비반복 읽기) | 동일한 데이터를 여러 번 조회할 때, 값이 변경됨 | 한 트랜잭션에서 조회 후, 다른 트랜잭션이 UPDATE하면 조회 결과가 다름 | REPEATABLE READ 이상 격리 수준 사용 |
Phantom Read (팬텀 충돌) | 동일한 조건으로 조회했을 때, 행이 추가/삭제되어 결과가 달라짐 | 첫 번째 조회 후, 다른 트랜잭션이 INSERT/DELETE하면 다시 조회할 때 결과가 다름 | SERIALIZABLE 격리 수준 사용 |
5. 결론
📌 팬텀 충돌(Phantom Conflict, Phantom Read)이란?
- 동일한 SELECT 쿼리를 여러 번 실행했을 때, 다른 트랜잭션이 데이터를 추가하거나 삭제하여 결과가 달라지는 문제
- 일반적으로 INSERT 또는 DELETE로 인해 발생 (UPDATE는 영향 없음)
📌 어떻게 해결할까?
- Serializable 격리 수준 사용 (
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
) - SELECT … FOR UPDATE 또는 공유 락 (
LOCK IN SHARE MODE
) 적용 - MySQL의 경우 Gap Lock 활용
🚀 트랜잭션 처리에서 팬텀 충돌을 방지하려면, 트랜잭션 격리 수준을 높이고 적절한 Lock을 활용해야 합니다!