본문 바로가기
DB/MySQL

DB Lock (s lock, x lock, index lock 등등)

by 계범 2023. 3. 26.

Lock 이란?

더보기

Lock은 데이터의 일관성을 유지하기 위해 사용하는 기능이다.

여러 클라이언트 간에 데이터에 접근하여 변경하거나 조회하는 것을 방지할 수 있다.

여기선 락의 종류와 해당 락들에 대해서 설명만 할 예정이다.

Shared Lock & Exclusive Lock

더보기

Shared Lock(S Lock, Read Lock)

읽기 잠금, 공유 잠금(락)으로 불린다.

해당 락을 설정하면 여러 클라이언트가 동시에 읽기 잡을 가능하게 허용하나, 쓰기 작업은 불가능하다.

Exclusive Lock(x Lock, Write Lock)

쓰기 잠금, 베타 잠금(락)으로 불린다.

해당 락을 설정하면 하나의 클라이언트가 쓰기 가능하나, 다른 클라이언트는 읽기,쓰기 둘 다 불가능하다.

Table Lock & Row Lock

더보기

Table Lock

table 단위로 lock을 거는 방식.

table에 lock 을 걸게 되고 해당 테이블을 사용하는 쿼리들은 lock이 해제될 때까지 대기한다.

// 잠금(읽기 잠금, 쓰기 잠금)
LOCK TABLES 테이블명 READ/WRITE

// 해제
UNLOCK TABLES 테이블명
// 테이블명 미 지정 시 전체 해제

Row Lock(Record Lock)

은 특정 행에 lock을 거는 방식.

해당 행을 사용하는 쿼리들만 lock이 걸리고, 다른 행에는 영향을 주지 않음.

따라서, row lock이 유용하게 사용됨.

x lock 예시

-- products 테이블에서 id=1인 행을 업데이트하는 쿼리 (FOR UPDATE 사용)
START TRANSACTION;
SELECT * FROM products WHERE id=1 FOR UPDATE;
UPDATE products SET price = 1000 WHERE id = 1;
COMMIT;

s lock 예시

-- products 테이블에서 id=2인 행을 조회하는 쿼리 (FOR SHARE 사용)
START TRANSACTION;
SELECT * FROM products WHERE id=2 FOR SHARE;
COMMIT;

Index Lock

더보기

Record Lock

위의 row lock형태와 동일하게 해당 인덱스 테이블의 record(row)에 걸린 것을 뜻함.

row lock을 걸 시, 해당 인덱스의 record에도 동일하게 lock이 걸림.

(index record lock, secondary lock이라고 불림)

Gap Lock

인덱스에서 조건에 일치하지 않는 레코드 간 간격(gap)을 막기 위한 lock이다.

read committed 이상의 격리 수준에서 발생한다.

 

범위 검색, order by, distinct 등에서 gap lock이 발생하며,

해당 범위 내에 데이터가 추가된다면 검색 시점과 다른 결과를 뱉을 수 있어서 데이터의 무결성을 헤치게 된다.

해당 범위 내에 존재하지 않는 값을 찾는 과정에서 다른 트랜잭션이 값을 추가하거나 변경하면 데이터 무결성 문제가 발생할 수 있다.

이러한 문제를 해결하기 위해 인덱스의 간격의 빈공간에 lock을 걸어 다른 트랜잭션이 해당 범위 내에 데이터를 추가하는 것을 방지한다.

Next-Key Lock

record lock과 gap lock이 복합적으로 사용되는 락.

범위 지정 쿼리 실행 시 해당하는 쿼리들 마다 record lock이 걸리고, 관련 범위는 gap lock이 걸리는 것을 합쳐서 next-key lock이라고 한다.

추가 참조 글 .. Page Lock

더보기

innoDB는 B+Tree 구조를 가지고 있고,

해당 구조에서 노드(페이지)단위로 묶어서 데이터를 저장하고 있다.

 

해당 페이지는 뮤텍스(key가 1개)로 락을 관리하고 있는데, 그렇기 때문에 read lock이여도 같은 페이지를 접근하게 된다면, 페이지 잠금에 의한 delay가 걸리게 된다.

추가 참조 글.. JPA 사용 시 Lock

더보기

다양한 상황마다 다르겠지만,

우리의 상황은 JPA(Hibernate 구현체) + maria DB에 entity에 별도로 @Version 어노테이션을 사용하지 않은 경우, mariaDB의 기본 격리 수준인 repeatable read를 적용하게 된다.

 

이로 인해 쿼리 실행 시 해당 레코드에 락이 걸린다.

 


참조

https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html

chatGPT

https://tech.kakao.com/2018/06/19/mysql-ascending-index-vs-descending-index/

https://www.letmecompile.com/mysql-innodb-lock-deadlock/

https://www.letmecompile.com/mysql-innodb-auto-increment-%EC%84%B1%EB%8A%A5-%EC%B5%9C%EC%A0%81%ED%99%94/

댓글