동시성 문제를 해결하기 위해 MySQL 스토리지 엔진(InnoDB) 은 Lock 기능을 제공합니다.
그 중 MySQL 디폴트 Isolation Level인 Repeatable Read 에서 사용되는 Record Lock, Gap Lock, Next-Key Lock 에 대하여 알아보겠습니다.
Record Lock 은 특정 레코드, 정확히 말하면 특정 인덱스에 Lock 을 거는 것입니다.
Record Lock 이 걸리면 다른 트랜잭션에서 Lock 이 걸린 인덱스에 insert, update ,delete 할 수 없습니다.
예를들어, 아래 쿼리를 실행 시켰다고 가정해 보겠습니다.
select * from student where age = 10 for update;
age 컬럼에 인덱스가 걸려있다면 age = 10 인 레코드에 대하여 다른 트랜잭션에서 update, insert, delete 를 실행할 경우 대기하게 됩니다.
만약 age 컬럼에 인덱스가 걸려있지 않다면 테이블 전체에 대하여 Lock 이 걸립니다.
Gap Lock 은 조회한 인덱스 사이의 Gap 에 거는 Lock 입니다.
Gap Lock 이 걸리면 다른 트랜잭션에서 Lock 이 걸린 인덱스에 insert 를 할 수 없습니다. (update, delete 가능)
어떤 말인지 감이 안올 수 있는데 예시를 들어보겠습니다.
| id(pk) | name | age(index) |
|---|---|---|
| 1 | minsu | 15 |
| 2 | kevin | 15 |
| 3 | tom | 15 |
| 4 | jack | 18 |
| 5 | suin | 19 |
| 6 | sangho | 19 |
위 테이블에서 아래의 Gap 이 생기게 됩니다.
() 소괄호: 초과, 미만
[] 대괄호: 이상, 이하
select * from student where age = 18 for update;
age = 18 로 조회했을 때 해당 인덱스 범위 양끝 gap인 16 ~ 17, 19 에 Gap Lock 이 걸립니다.
select * from student where age = 19 for update;
age = 19 로 조회했을 때에는 20 ~ 무한 에 Gap Lock 이 걸립니다.
select * from student where age between 15 and 18 for update;
해당 조건에서는 -무한 ~ 14, 19 에 Gap Lock 이 걸립니다.
select * from student where age = 30 for update;
해당 조건에서는 20 ~ 무한 에 Gap Lock 이 걸립니다.
select * from student where id = 3 for update;
이렇게 조회했을 때는 어떨까요. 해당 케이스는 Gap Lock 이 걸리지 않습니다. pk 로 조회했기 떄문이죠. Primary Key 또는 Unique Key 로 where 조건을 설정한 경우 해당 범위를 벗어나는 곳에는 Gap Lock 이 걸리지 않습니다.
Record Lock 과 Gap Lock 이 함께 사용되는 것을 Next-Key Lock 이라고 부릅니다.
Gap Lock 은 단독적으로 사용되지 않고 Next-Key Lock 의 일부로 사용됩니다.
select * from student where age between 15 and 18 for update;
해당 조건에서 -무한 ~ 14, 19 에는 Gap Lock 이 걸리고, 15 ~ 18 에는 Record Lock 이 걸립니다.