https://www.maeil-mail.kr/question/93
요약: 갭 락과 넥스트 키 락을 사용해서 Phantom Read를 방지 할 수 있다.
다음과 같은 상황을 살펴보자
트랜잭션 a: select * from table where id>1;,select * from table where id>1;,
트랜잭션 b Insert into table (a,b,c) values(a,b,c)
트랜잭션 a는 두번의 읽기 과정을 수행하고 b는 a에서 읽어들여지는 데이터를 수정한다. 이 때 만약 a의 두번의 읽기 사이에 b의 update쿼리가 수행된다면 a에서 읽어들여지는 두번의 select문의 결과가 다르게 될 것이다.
이렇게 같은 트랜잭션내에서 같은 읽기의 작업을 수행했는데, 다른 값이 나오는 것을 Phantom Read
라고 한다.
출처: https://gisungcu.tistory.com/645
인덱스와 인덱스 사이에 있는 빈공간을 락을 걸어서 위의 사례처럼 발생이 안되게 할 수 있다.
이를 Gap Lock
이라고 한다.
Gap Lock
을 이용하면, 특정 select 문을 사용하고 있을 때 빈 공간 즉 Gap에 락을 걸어서,
다른 트랜잭션에서 접근하여 삽입하는 요청을 기다리게한다. 기다린 write 요청은 락이 해제되면 그 후에 수행하여, phantom read
를 막을 수 있다.
Next Key Lock
은 특정 레코드와 위의 gap에 락을 거는 범위를 지정해서 락을 거는 것이다.
아래의 코드를 통해서 잠금이 가능하다.
- 트랜잭션 1 (Session 1)
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION;
-- age가 25 이상 35 이하인 데이터를 조회하면서 FOR UPDATE로 잠금
SELECT * FROM users WHERE age BETWEEN 25 AND 35 FOR UPDATE;
-- 트랜잭션 2 (Session 2)
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION;
-- 새로운 레코드 삽입 시도
INSERT INTO users (name, age) VALUES ('David', 28);
이 때 트랜잭션 2는 1이 끝날 때까지 기다린 후에 실행되어서 phantom read
를 막을 수 있다.