트랜잭션이 본 스냅샷을 계속 사용하므로, 나중에 생긴 행은 현재 시점의 조회 대상에서 빠집니다.
핵심은 하나입니다. 일관된 읽기는 새 행을 보이지 않게 유지하고, 잠금 읽기는 새 행이 들어오지 못하게 대기시킵니다.
T1이 age > 20 범위를 읽은 뒤 다시 같은 조건을 조회하는 동안, T2가 age = 25 행을 INSERT하려고 합니다. 팬텀 리드는 이 새 행이 재조회 결과에 끼어드는 문제입니다.
SELECT
SELECT ... FOR UPDATE
트랜잭션이 본 스냅샷을 계속 사용하므로, 나중에 생긴 행은 현재 시점의 조회 대상에서 빠집니다.
현재 읽기는 최신 값을 다루려 하므로, 범위 안에 새 행이 생기지 못하게 막아야 같은 결과를 유지할 수 있습니다.
새 행은 실제로 추가되지만, T1의 스냅샷에는 포함되지 않아서 이번 조회에서는 보이지 않습니다.
Gap Lock이 age > 20 범위의 빈 공간까지 잠가서, 팬텀 후보 행이 들어오는 순간 자체를 지연시킵니다.
새 행이 존재해도 T1은 계속 못 보므로, 팬텀은 가시성 제어로 사라집니다.
T2가 대기 중이므로 재조회 시점에는 끼어들 행이 없고, 팬텀은 삽입 차단으로 막힙니다.
조회는 락 경쟁을 줄이고도 같은 결과를 보장할 수 있습니다.
현재 읽기에서는 MVCC만으로 부족하므로, Next-Key Lock의 Gap Lock이 팬텀을 직접 막습니다.
팬텀 방지는 한 가지 메커니즘이 아닙니다. MVCC의 스냅샷 읽기는 새 행을 안 보이게 만들고, 잠금 읽기는 새 행이 못 들어오게 만들어서 같은 범위의 결과를 안정적으로 유지합니다.