MySQL Lock
Row Level Lock
Shared Lock
Shared Lock은 특정 Row를 읽을 때 사용되는 Lock 입니다. Shared Lock끼리는 동시에 접근이 가능합니다. 즉 하나의 row를 여러 트랜잭션이 동시에 읽을 수 있다는 것입니다. 하지만 Shared Lock이 설정된 Row에 Exclusive Lock을 사용할 수는 없습니다. 즉, 특정 Row를 누가 읽고 있음으로 Shared Lock이 설정되어 있는데, 다른 사용자가 그 데이터에 쓰기 작업을 하기 위해 Exclusive Lock을 걸 수 없다는 의미입니다.
일반적인 Select 쿼리는 Lock을 사용하지 않고 DB를 읽어 들입니다. 하지만 Select ... FOR Share 등 일부 Select 쿼리는 특정 Row를 읽을 때 InnoDB 각각 Row에 Shared Lock을 걸어줍니다.
Exclusive Lock
Exclusive Lock은 특정 Row를 변경하고자 할 때 사용됩니다. 특정 Row에 Exclusive Lock이 해제될 때까지, 다른 트랜잭션은 읽기 작업을 하기 위해 Shared Lock을 걸거나 쓰기 작업을 위해 Exclusive Lock을 걸 수 없습니다.
Exclusive Lock은 Select...For Update나 Update, Selete 등의 수정 쿼리를 날릴 때 각 Row에 걸리는 Lock 입니다.
Record Lock
Record Lock이란 row의 index를 기준으로 Lock을 거는 것을 말합니다. Record Lock으로 가져오게 되면 다른 트랜잭션에서 해당 index의 row에 insert, update, delete 구문 사용이 Lock이 걸려있는 동안은 사용 불가하게 됩니다.
Record Lock은 index를 기준으로 Lock을 건다고 설명했는데요. 그러면 index를 설정하지 않으면 Record Lock은 돌아가지 않을까요? 사실 우리가 index를 명시적으로 설정하지 않아도 MySQL(InnoDB)은 숨겨진 clustered index를 건다고 합니다. 따라서 아무런 index를 걸지 않았따면 숨겨진 index를 통해 Lock이 걸릴 것입니다.
Gap Lock
Gap Lock은 DB index record의 gap에 걸리는 Lock입니다. 여기서 gap이란 index 중 DB에 실제 record가 없는 부분입니다.
예를 들자면 id column만 있는 테이블이 있고, id column에 index가 걸려있다고 합니다. 현재 테이블에는 id = 3인 row와 id = 7인 row가 있습니다. 그러면 DB와 index는 아래 그림과 같은 상태일 것입니다.
그러면 현재 id <= 2, 4 <= id <= 6, id >= 8 에 해당하는 부분에는 index record가 없습니다. 이 부분이 바로 index record의 gap입니다. 그리고 Gap Lock은 이러한 gap에 걸리는 Lock입니다. 즉, Gap Lock은 해당 gap에 접근하려는 다른 쿼리의 접근을 막습니다. Gap Lock은 조건에 해당하는 새로운 Row가 추가되는 것을 방지하기 위해 존재하는 Lock입니다.
Gap Lock에 대한 예시를 살펴봅니다. t라는 테이블에 c1 컬럼만 존재하는데 c1 컬럼에는 13, 17 두 값밖에 존재하지 않습니다.
SELECT c1 FROM t WHERE c1 BETWEEN 10 AND 20 FOR UPDATE
위와 같이 실행되면 t.c1의 값이 10과 20 사이 중 실제 record가 없는 부분인 gap에 Lock이 걸립니다. 이 상태에서 다른 트랜잭션이 t.c1 = 15인 row를 삽입하려고하면 Gap Lock 때문에 commit 되거나 rollback 될 때까지 삽입되지 않습니다.
Next-Key Lock
Insert Intention Lock
Insert Intention Lock은 Insert 구문이 실행될 때 InnoDB 엔진 내부족으로 implicit하게 획득하는 특수한 형태의 Gap Lock입니다. 여러 개의 트랜잭션들이 gap 안의 다른 위치에 Insert를 동시 수행할 때 기다릴 필요가 없도록 하는 것이 목적입니다.