14.2.7 넥스트키 로크에 의한 팬텀 문제 해결
같은 쿼리에서 다양한 시간에 다양한 행 세트가 생성되면 이른바 팬텀의 문제가 트랜잭션 내에서 발생합니다. 예를 들어, SELECT
가 두 번 실행되었지만, 1 회째는 반환되지 않은 행 두 번째는 반환 된 경우, 그 행이 「팬텀」행입니다.
child
테이블의 id
컬럼에 인덱스가 식별자의 값이 100보다 큰 모든 행을 테이블에서 읽기, 선택된 행의 일부 열을 나중에 업데이트하겠다는 의도 잠금한다고 가정합니다.
SELECT * FROM child WHERE id> 100 FOR UPDATE;
쿼리는 id
가 100보다 큰 첫 번째 레코드에서 인덱스가 스캔됩니다. 이 테이블에는 id
값이 90과 102의 행이 포함되어있는 것으로합니다. 검색 범위 내의 인덱스 레코드에 설정된 잠금은 갭 (이 경우 간격은 90에서 102까지)에 삽입이 잠겨 있지 않은 경우는 다른 세션 id
가 101의 새로운 라인을 그 테이블에 삽입 할 수 있습니다. 같은 트랜잭션 내에서 동일한 SELECT
를 실행하면 쿼리에서 반환 된 결과 집합에 id
가 101의 새로운 라인 ( 「팬텀」)이 포함되어 있습니다. 일련의 행을 데이터 항목 간주하면,이 새로운 팬텀 아이는 "트랜잭션 동안 읽을 데이터가 변경되지 않도록 트랜잭션을 수행 할 수 있어야한다"는 트랜잭션의 분리 원칙을 위반하고 있습니다.
팬텀의 발생을 피할 수 있도록, InnoDB
는 일반적으로 인덱스 행 잠금 및 갭 잠금을 결합한 넥스트 키 잠금라는 알고리즘이 사용됩니다. InnoDB
는 테이블 인덱스를 검색 또는 스캔 할 때 생성 된 인덱스 레코드에 공유 락 또는 배타 락을 설정하는 방법으로 행 수준 잠금을 실행합니다. 따라서 행 레벨 락은 실제로 인덱스 레코드 잠금입니다. 게다가 어느 인덱스 레코드에 넥스트 키 잠금은 인덱스 레코드 앞의 '갭'에도 영향을받습니다. 즉, 넥스트 키 잠금은 인덱스 레코드 잠금과 그 인덱스 레코드의 전의 갭에 대한 갭 잠금을 조합 한 것입니다. 세션이 인덱스의 레코드 R
에 공유 락 또는 배타 락을 가지고 있다면, 다른 세션이 인덱스 순서로 R
의 직전에있는 갭에 새로운 인덱스 레코드를 삽입 할 수 없습니다.
InnoDB
는 인덱스를 스캔 할 때 인덱스의 마지막 레코드의 뒤의 갭을 잠글 수도 있습니다. 위의 예에서는 바로 그것이 이루어지고 있습니다. id
가 100보다 큰 테이블에 삽입되는 것을 방지되도록 InnoDB
에서 설정된 잠금은 id
값 102의 뒤의 갭에 대한 잠금이 포함되어 있습니다.
넥스트 키 잠금을 사용하면 응용 프로그램에 고유 체크를 구현할 수 있습니다. 공유 모드에서 데이터를 읽을 때 삽입되는 행의 중복이 보여야 행을 안전하게 삽입 할 수있어 읽는 동안 후속 행에 설정된 넥스트 키 잠금은 모든 사용자가 중복 행 삽입이 방지되는 것을 확인할 수 있습니다. 따라서 넥스트 키 잠금을 사용하면 테이블에 존재하지 않는 것도 "잠금"할 수 있습니다.
갭 잠금은 섹션 14.2.6 "InnoDB 레코드 격차 및 넥스트 키 잠금" 에서 설명한 방법으로 해제 할 수 있습니다. 갭 잠금이 해제되어 있으면 다른 세션에서 새 행을 갭에 삽입 할 수 있기 때문에 팬텀의 문제가 발생할 수 있습니다.