[MySQL] 조회 쿼리에서 FOR UPDATE 쓰기잠금 실험

[MySQL] 조회 쿼리에서 FOR UPDATE 쓰기잠금 실험

RealMySQL 책을 읽으면서

 책 내용중 트랜잭션 격리수준에 대해 다루면서 REPEATABLE READPHANTOM READ에 대한 설명이 있었는데 FOR UPDATE를 이용하여 쓰기잠금을 조회 쿼리에 걸었을 때 PHANTOM READ가 발생할 수 있다 설명하고 있었다.

 그러나 내가 공부한 내용으로는 PHANTOM READ가 일어나기 전에 예시 그림 자체가 GAP LOCK에 의해 트랜잭션 자체가 진행되지 않는다고 판단했고 이를 실험하기 위해 직접 예시 코드를 수행해봤다.

잠금을 기다리다가 타임아웃 된 상황

실험해본 결과는 내 생각대로 INSERT를 하기위해 트랜잭션이 쓰기잠금을 얻기 위해 기다리다가 타임아웃 되었다.

InnoDB 잠금에 대한 일부 내용

RECORD LOCK

레코드 자체만을 잠구는 것을 레코드 락이라고 하며 InnoDB의 경우 인덱스의 레코드를 잠근다.

GAP LOCK

레코드 자체가 아니라 레코드와 바로 인접한 레코드 사이의 간격만을 잠그는 것을 의미한다.
ex) id > 30 AND id < 50 FOR UPDATE 31부터 49까지 레코드가 있던 없던 잠금이 걸린다.

NEXT KEY LOCK

레코드락과 갭락을 합쳐 놓은 형태의 잠금이다.

begin; //트랜잭션 시작
select name from study where id >= 1 for update; // 여기서 GAP LOCK이 걸린다.

첫번째 트랜잭션

 위 트랜잭션은 FOR UPDATE를 통해 id가 1이상인 경우 모든 행에 대한 잠금을 걸게된다.
여기서 id는 실제 데이터가 존재하던 존재하지 않던 상관없다.

그리고 COMMIT하지 않은 상태에서 두번째 트랜잭션이 INSERT 하려고 한다.

begin;
insert into study(name) values('lock-test'); //위의 FOR UPDATE 쓰기잠금이 걸려있어 쓰기 작업을 수행할 수 없다.

두번째 트랜잭션

 MySQL Shell에서 실험했을 때 두번째 트랜잭션에서 INSERT를 하게되면 잠금을 기다리게 되어 쿼리를 입력할 수 없는 상태가 된다. 만약 INSERT를 수행하려고 했다면 첫번째 트랜잭션을 COMMIT했어야 한다.

결론

 책에서는 엄밀히 말하면 PHANTOM READ현상이 발생할 수 있다 라고 나와있었지만 트랜잭션 내의 쿼리가 처리되면서 MVCC를 통해 PHANTOM READ현상이 발생하지 않는다고 알고 있었고 여전히 그렇다.

 뭔가 예시가 잘못된건지 내가 제대로 이해를 못한건지 모르겠다. 더 낮은 격리 수준에선 PHANTOM READ가 발생할 수 있지만 적어도 REPEATABE READ격리 수준에선 발생하지 않는다고 생각한다.