MySQL에서 사용되는 잠금은 크게 스토리지 엔진 레벨과 MySQL 엔진 레벨로 나눠볼 수 있다. MySQL엔진 레벨의 잠금은 모든 스토리지 엔진에 영향을 미치지만, 스토리지 엔진 레벨의 잠금은 스토리지 엔진 간 상호 영향을 미치지는 않는다. MySQL 엔진에서의 각 잠금의 특징과 이러한 잠금이 언제 사용되는지에 대해 알아보자!
00. 글로벌 락(GLOBAL LOCK)
글로벌 락은 MySQL에서 제공하는 잠금 가운데 가장 범위가 크며, 아래의 명령으로만 획득할 수 있다.
mysql> FLUSH TABLES WITH READ LOCK;
이 명령은 실행과 동시에 MySQL 서버에 존재하는 모든 테이블의 잠금을 걸며, 작업 대상 데이터베이스가 다르더라도 동일한 영향을 미친다. 그런데 "FLUSH TABLES WITH READ LOCK" 명령은 테이블에 읽기 잠금만 걸기 전에 먼저 테이블을 FLUSH해야하기 때문에, 테이블에 실행되고 있는 모든 종류의 쿼리가 완료되어야만 테이블을 FLUSH하고 잠금을 걸 수 있다. 즉, 장시간 SELECT 쿼리가 실행되고 있을 때는 이 SELECT쿼리가 종료된 후에야 명령을 수행할 수 있다. 글로벌 락은 MySQL 서버의 모든 테이블에 큰 영향을 미치기 때문에 웹 서비스용으로 사용되는 MySQL 서버에서는 가급적 사용하지 않는 것이 좋다.
01. 테이블 락(TABLE LOCK)
개별 테이블 단위로 설정되는 잠금이며, 명시적으로는 아래의 명령으로 특정 테이블의 락을 획득할 수 있다.
mysql> LOCK TABLES table_name [READ|WRITE];
명시적으로 획득한 잠금은 "UNLOCK TABLES" 명령으로 잠금을 해제할 수 있으며, 테이블 락은 MyISAM 뿐만 아닐 InnoDB에서도 동일하게 설정할 수 있다.
묵시적인 테이블 락은 MyISAM이나 MEMORY 테이블에 데이터를 변경하는 쿼리를 실행했을 때 자동으로 획득됐다가 쿼리가 끝나면 자동으로 해제된다. 하지만 InnoDB의 경우 스토리지 엔진 차원에서 레코드 기반의 잠금을 제공하기 때문에 묵시적 테이블 락이 설정되지는 않는다.
02. 유저 락(USER LOCK)
이 잠금의 특징은 대상이 테이블이나 레코드가 아닌, 사용자가 지정한 문자열(String)에 대해 획득하고 해제하는 잠금이라는 점이다. "GET_LOCK()" 함수를 이용하여 잠금을 설정할 수 있다.
유저 락은 여러 클라이언트가 상호 동기화를 처리해야 할 때나, 많은 레코드를 한 번에 변경하는 트랜잭션의 경우에 유용하게 사용할 수 있다.
아래의 예시를 통해 유저 락의 획득과 해제 방법을 알아보자.
-- // "mylock"이라는 문자열에 대해 잠금을 획득한다.
-- // 이미 잠금이 사용 중이라면 3초 동안 대기한다.
mysql> SELECT GET_LOCK('mylock', 3);
-- // "mylock"이라는 문자열에 대해 잠금이 설정되어 있는지 확인한다.
mysql> SELECT IS_FREE_LOCK('mylock');
-- // "mylock"이라는 문자열에 대해 획득한 잠금을 해제한다.
mysql> SELECT RELEASE_LOCK('mylock');
-- // 3개 함수 모두 정상적으로 LOCK을 획득하거나 해제한 경우 1을, 아니면 0이나 NULL을 반환한다.
03. 네임 락(NAME LOCK)
데이터베이스 객체(테이블이나 뷰 등)의 이름을 변경할 경우 자동으로 획득하는 잠금이다.
mysql> RENAME TABLE tab_a TO tab_b;
RENAME TABLE 명령의 경우 원본 이름과 변경될 이름 두 개 모두 한꺼번에 잠금을 설정한다.
실시간으로 테이블을 바꿔야 하는 요건이 배치 프로그램에서 자주 발생되는데, 이런 경우 하나의 RENAME TABLE에 두 RENAME 작업을 한꺼번에 실행해야 한다. 아래의 예제를 통해 알아보자.
-- // 배치 프로그램에서 별도의 임시 테이블(rank_new)에 서비스용 랭킹 데이터 생성
-- // 랭킹 배치가 완료되면 현재 서비스용 랭킹 테이블(rank)을 rank_backup으로 백업하고
-- // 새로 만들어진 랭킹 테이블(rank_new)을 서비스용으로 대체하고자 하는 경우
mysql> RENAME TABLE rank TO rank_backup, rank_new TO rank;
하지만 이 문장을 아래와 같이 2개로 나눠 실행하면 아주 짧은 시간 동안 'rank'테이블이 존재하지 않는 순간이 생기고, 'Table not found 'rank'" 오류를 발생시킨다.
mysql> RENAME TABLE rank TO rank_backup;
mysql> RENAME TABLE rank_new TO rank;
'MySQL' 카테고리의 다른 글
05. InnoDB 트랜잭션 처리 및 로그(Undo/Redo) 관리 (0) | 2020.06.23 |
---|---|
04. MySQL에서의 잠금 - (2) MyISAM과 MEMORY 스토리지 엔진 (0) | 2020.06.15 |
03. 트랜잭션 (0) | 2020.06.15 |
02. InnoDB 스토리지 엔진 아키텍처 (0) | 2020.06.13 |
01. MySQL 아키텍처 (0) | 2020.06.13 |