해결된 질문
작성
·
185
0
안녕하세요.
예시를 위해 테이블명을 변경했습니다. 도메인상 이해안되도 이해부탁드립니다..!
바로 질문으로 들어가면 아래에 쿼리를 발생시키면 supremum pseudo-record 락이 생기게 됩니다. 하지만 여기서 다른 세션에서 아래 쿼리를 똑같이 실행하면 select for update에서 락대기가 걸릴거라고 예상했는데
START TRANSACTION; #1
#reader_id+name 조합으로 유니크인덱스 사용중
SELECT * FROM book b
WHERE reader_id = 21 AND name = 'ABC' FOR UPDATE; #2
INSERT INTO book
VALUES (null, 'ABC', 21); #3
아래 처럼 같은 락이 추가됩니다. 그래서 두 세션중 어느세션에서 insert 쿼리를 입력하든 Lock 대기가 걸리게됩니다. select에서 락대기가 걸리길 바랬는데 insert를 해야 락대기가 걸리는 이유가 무엇인가요?
답변 미리 감사합니다.
답변 2
0
안녕하세요.
SELECT .. WHERE ... FOR UPDATE
쿼리에서 WHERE
절에 일치하는 레코드가 없으면,
MySQL 서버는 다른 세션에서 WHERE 절에 일치하는 레코드가 INSERT되지 못하도록 Gap Lock을 걸게 됩니다. 그게 첫번째 그림의 Supremum pseudo-record - X lock
이에요. 근데 Gap lock은 X-lock과 S-Lock으로 구분되긴 하지만 사실 둘 모두 S-lock으로 작동합니다. 즉, Gap lock은 X-lock끼리도 호환이 되어서, 두 세션에서 SELECT .. WHERE .. FOR UPDATE 문장이 아무런 잠금 경합없이 동시에 실행 가능하게 되는 것입니다.
감사합니다.
0
안녕하세요, 인프런 AI 인턴입니다.
님께서 궁금해하시는 상황은 MySQL에서 고유 인덱스에 존재하지 않는 데이터에 대해 SELECT ... FOR UPDATE
를 사용할 때 발생하는 행위와 관련이 있습니다. MySQL의 InnoDB 스토리지 엔진에서는 SELECT ... FOR UPDATE
쿼리를 수행할 때 해당 조건에 부합하는 데이터가 존재하지 않으면, InnoDB는 의도적으로 “next-key lock”을 사용합니다. 이는 지정된 검색 조건과 일치하는 데이터가 없을 경우에도, 해당 범위 내에서 데이터의 삽입을 방지하기 위해 설정되는 락입니다.
이 “next-key lock”의 특징은 범위에 속하는 데이터의 추가를 방지하여 동시성을 관리하는 데 있습니다. 그렇기 때문에 다른 세션에서 동일한 범위에 대해 INSERT
를 시도하면 이미 설정된 “next-key lock” 때문에 대기 상태가 됩니다. 여기서 “supremum pseudo-record” 락은 특정 키 값보다 더 큰 값에 대한 가상의 레코드에 락을 설정하는 것으로, 신규 삽입이 예정된 영역의 경계를 관리합니다.
이러한 고유 인덱스를 사용하지 않는 데이터에 SELECT ... FOR UPDATE
를 사용할 때 발생하는 이 락 대기 현상은, 동시에 같은 조건으로 삽입하려는 다른 트랜잭션이 있을 경우, 데드락을 방지하고 일관성을 유지하기 위한 MySQL InnoDB의 설계 원리입니다.
데이터가 실제로 존재하지 않아 SELECT ... FOR UPDATE
에서 바로 락 대기 상태에 들어가지 않는 것으로 보이나, 실제로는 해당 영역에 데이터를 삽입하려고 할 때 이미 설정된 “next-key lock”에 의해 대기 상태에 들어가게 됩니다. 이 과정은 두 세션 모두에 적용되어 어느 한 세션이 락을 획득하고 작업을 완료할 때까지 다른 세션은 대기하게 되는 것입니다.
이러한 메커니즘은 동일한 데이터에 대한 변경 사항이 동시에 발생하는 것을 방지하고, 데이터 무결성과 일관성을 보장하는 데 중요한 역할을 합니다.