LOCK
LOCK
하나 이상의 테이블을 잠그는 명령이에요. 다중 트랜잭션이 동시에 테이블에 접근할 때 PostgreSQL은 각 명령에 대해 필요한 가장 덜 제한적인 락을 자동으로 걸지만, 더 제한적인 락이 필요할 때 LOCK TABLE로 명시적으로 잠글 수 있어요. 락은 현재 트랜잭션이 끝날 때까지 유지돼요.
출처: PostgreSQL 문서
본문
개요 (Synopsis)
LOCK [ TABLE ] [ ONLY ] name [ * ] [, ...] [ IN lockmode MODE ] [ NOWAIT ]
where lockmode is one of:
ACCESS SHARE | ROW SHARE | ROW EXCLUSIVE | SHARE UPDATE EXCLUSIVE
| SHARE | SHARE ROW EXCLUSIVE | EXCLUSIVE | ACCESS EXCLUSIVE
설명 (Description)
LOCK TABLE은 테이블 수준 락을 획득하며, 필요하면 충돌하는 락이 해제될 때까지 대기해요. NOWAIT가 지정되면 LOCK TABLE은 원하는 락을 획득하기 위해 대기하지 않아요. 즉시 획득할 수 없으면 명령이 중단되고 오류가 발생해요. 일단 획득되면 락은 현재 트랜잭션의 나머지 동안 유지돼요. (UNLOCK TABLE 명령은 없어요. 락은 항상 트랜잭션 종료 시 해제돼요.)
뷰가 잠기면 뷰 정의 쿼리에 나타나는 모든 릴레이션도 같은 락 모드로 재귀적으로 잠겨요.
테이블을 참조하는 명령에 대해 락을 자동으로 획득할 때, PostgreSQL은 항상 가능한 가장 덜 제한적인 락 모드를 사용해요. LOCK TABLE은 더 제한적인 락이 필요할 수 있는 경우를 위한 거예요. 예를 들어 애플리케이션이 READ COMMITTED 격리 수준으로 트랜잭션을 실행하면서 트랜잭션 동안 테이블의 데이터가 안정적으로 유지되도록 보장해야 한다고 가정해 보세요. 이를 위해 쿼리하기 전에 테이블에 SHARE 락 모드를 획득할 수 있어요. SHARE 락 모드는 쓰기 작업이 획득하는 ROW EXCLUSIVE 락과 충돌하므로, 이렇게 하면 동시 데이터 변경을 막고 테이블의 이후 읽기가 커밋된 데이터의 안정적인 뷰를 보도록 보장해요. 그리고 여러분의 LOCK TABLE name IN SHARE MODE 명령문은 ROW EXCLUSIVE 모드 락을 보유한 동시 세션이 커밋하거나 롤백할 때까지 대기해요. 따라서 락을 획득하면 커밋되지 않은 쓰기가 남아 있지 않게 되고, 락을 해제하기 전까지 새 쓰기도 시작할 수 없어요.
REPEATABLE READ나 SERIALIZABLE 격리 수준으로 트랜잭션을 실행할 때 비슷한 효과를 얻으려면, SELECT나 데이터 수정 명령문을 실행하기 전에 LOCK TABLE 명령문을 실행해야 해요. REPEATABLE READ나 SERIALIZABLE 트랜잭션의 데이터 뷰는 첫 SELECT나 데이터 수정 명령문이 시작될 때 고정돼요. 트랜잭션 안의 나중 시점에 LOCK TABLE을 실행해도 동시 쓰기는 여전히 막을 수 있지만, 트랜잭션이 읽는 것이 최신 커밋 값과 일치하도록 보장하지는 않아요.
이런 종류의 트랜잭션이 테이블의 데이터를 변경하려 한다면, SHARE 모드 대신 SHARE ROW EXCLUSIVE 락 모드를 사용해야 해요. 이렇게 하면 한 번에 하나의 이런 유형의 트랜잭션만 실행되도록 보장돼요. 이렇게 하지 않으면 교착 상태(deadlock)가 발생할 수 있어요. 두 트랜잭션이 모두 SHARE 모드를 획득한 다음, 실제로 갱신을 수행하기 위해 ROW EXCLUSIVE 모드도 획득하지 못할 수 있기 때문이에요. (트랜잭션 자신의 락은 절대 충돌하지 않으므로, 트랜잭션은 SHARE 모드를 보유한 상태에서 ROW EXCLUSIVE 모드를 획득할 수 있어요 — 하지만 다른 누군가가 SHARE 모드를 보유하고 있다면 그럴 수 없어요.) 교착 상태를 피하려면 모든 트랜잭션이 같은 객체에 대해 같은 순서로 락을 획득하도록 하고, 단일 객체에 여러 락 모드가 관련된다면 항상 가장 제한적인 모드를 먼저 획득하도록 하세요.
락 모드와 잠금 전략에 대한 자세한 내용은 13.3절에서 확인할 수 있어요.
파라미터 (Parameters)
*name* — 잠글 기존 테이블의 이름이에요(선택적으로 스키마 한정). 테이블 이름 앞에 ONLY가 지정되면 그 테이블만 잠겨요. ONLY가 지정되지 않으면 테이블과 그 모든 하위 테이블(있을 경우)이 잠겨요. 선택적으로 테이블 이름 뒤에 *를 지정해 하위 테이블이 포함됨을 명시적으로 나타낼 수 있어요.
LOCK TABLE a, b; 명령은 LOCK TABLE a; LOCK TABLE b;와 동등해요. 테이블은 LOCK TABLE 명령에 지정된 순서대로 하나씩 잠겨요.
*lockmode* — 이 락이 어떤 락과 충돌하는지 지정해요. 락 모드는 13.3절에 설명되어 있어요. 락 모드를 지정하지 않으면 가장 제한적인 모드인 ACCESS EXCLUSIVE가 사용돼요.
NOWAIT — LOCK TABLE이 충돌하는 락이 해제되기를 기다리지 않아야 한다고 지정해요. 지정된 락을 기다리지 않고 즉시 획득할 수 없으면 트랜잭션이 중단돼요.
참고 (Notes)
테이블을 잠그려면 사용자가 지정된 lockmode에 대한 올바른 권한을 가져야 해요. 사용자가 테이블에 MAINTAIN, UPDATE, DELETE, TRUNCATE 권한이 있으면 어떤 lockmode든 허용돼요. INSERT 권한이 있으면 ROW EXCLUSIVE MODE(또는 13.3절에 설명된 대로 덜 충돌하는 모드)가 허용돼요. SELECT 권한이 있으면 ACCESS SHARE MODE가 허용돼요.
뷰에 락을 거는 사용자는 뷰에 대한 해당 권한이 있어야 해요. 또한 기본적으로 뷰의 소유자는 기본(base) 릴레이션에 대한 관련 권한이 있어야 하며, 락을 거는 사용자는 기본 릴레이션에 대한 어떤 권한도 필요하지 않아요. 하지만 뷰에 security_invoker가 true로 설정되어 있으면(CREATE VIEW 참고), 락을 거는 사용자가 뷰 소유자 대신 기본 릴레이션에 대한 관련 권한을 가져야 해요.
LOCK TABLE은 트랜잭션 블록 밖에서는 쓸모없어요. 락이 명령문이 완료될 때까지만 유지될 것이기 때문이에요. 따라서 PostgreSQL은 LOCK이 트랜잭션 블록 밖에서 사용되면 오류를 보고해요. 트랜잭션 블록을 정의하려면 BEGIN과 COMMIT(또는 ROLLBACK)을 사용하세요.
LOCK TABLE은 오직 테이블 수준 락만 다루므로, ROW가 포함된 모드 이름은 모두 잘못된 이름이에요. 이런 모드 이름은 일반적으로 잠긴 테이블 안에서 행 수준 락을 획득하려는 사용자의 의도를 나타내는 것으로 읽어야 해요. 또한 ROW EXCLUSIVE 모드는 공유 가능한(shareable) 테이블 락이에요. LOCK TABLE에 관한 한 모든 락 모드가 동일한 의미를 가지며, 어느 모드가 어느 모드와 충돌하는지에 대한 규칙만 다르다는 점을 명심하세요. 실제 행 수준 락을 획득하는 방법은 13.3.2절과 SELECT 문서의 “The Locking Clause”를 참고하세요.
예제 (Examples)
외래 키 테이블에 삽입을 수행할 때 기본 키 테이블에 SHARE 락을 획득하려면:
BEGIN WORK;
LOCK TABLE films IN SHARE MODE;
SELECT id FROM films
WHERE name = 'Star Wars: Episode I - The Phantom Menace';
-- Do ROLLBACK if record was not returned
INSERT INTO films_user_comments VALUES
(_id_, 'GREAT! I was waiting for it for so long!');
COMMIT WORK;
삭제 연산을 수행할 때 기본 키 테이블에 SHARE ROW EXCLUSIVE 락을 획득하려면:
BEGIN WORK;
LOCK TABLE films IN SHARE ROW EXCLUSIVE MODE;
DELETE FROM films_user_comments WHERE id IN
(SELECT id FROM films WHERE rating < 5);
DELETE FROM films WHERE rating < 5;
COMMIT WORK;
호환성 (Compatibility)
SQL 표준에는 LOCK TABLE이 없어요. 표준은 대신 SET TRANSACTION을 사용해 트랜잭션에 동시성 수준을 지정해요. PostgreSQL도 그것을 지원해요. 자세한 내용은 SET TRANSACTION을 참고하세요.
ACCESS SHARE, ACCESS EXCLUSIVE, SHARE UPDATE EXCLUSIVE 락 모드를 제외하고, PostgreSQL 락 모드와 LOCK TABLE 문법은 Oracle에 있는 것과 호환돼요.
더 알아보기 (Learn more)
락 모드와 잠금 전략의 자세한 내용은 “Locking and Indexes”와 “Table-level Locks” 절(13.3절)을 함께 보면 좋아요.