이 페이지에서는 반복 가능한 읽기 격리 수준에서 FOR UPDATE 절을 사용하는 방법을 설명합니다.
FOR UPDATE 절의 잠금 메커니즘은 반복 가능한 읽기 격리 수준과 직렬화 가능한 격리 수준에서 다르게 동작합니다. 직렬화 가능한 격리 수준과는 달리, 반복 가능한 읽기 격리 수준에서는 FOR UPDATE 절이 잠금을 획득하지 않습니다. FOR UPDATE의 잠금 동작에 대한 자세한 내용은 직렬화 가능한 격리 수준에서 SELECT FOR UPDATE 사용을 참조하세요.
FOR UPDATE 절 사용 방법에 대한 자세한 내용은 GoogleSQL 및 PostgreSQL FOR UPDATE 참조 가이드를 참조하세요.
FOR UPDATE 절을 사용하는 이유
트랜잭션이 반복 가능한 읽기 격리 수준에서 실행될 때, SELECT 문으로 쿼리된 데이터는 항상 해당 트랜잭션의 확정된 스냅샷 타임스탬프 시점의 데이터로 반환됩니다. 그 후 트랜잭션이 쿼리된 데이터를 기반으로 업데이트를 수행하면, 동시에 실행되는 다른 트랜잭션이 같은 데이터를 업데이트하는 경우 올바르지 않은 결과가 발생할 수 있습니다. 자세한 내용은 읽기-쓰기 충돌 및 정합성을 참조하세요.
트랜잭션이 커밋될 때 SELECT 문으로 쿼리한 데이터가 여전히 유효하도록 보장하려면, 반복 가능한 읽기 격리 수준에서 FOR UPDATE 절을 사용할 수 있습니다. FOR UPDATE를 사용하면, 데이터가 읽힌 시점과 수정된 시점 사이에 다른 트랜잭션이 데이터를 변경했더라도 트랜잭션의 정합성이 보장됩니다.
쿼리 구문
이 섹션에서는 FOR UPDATE 절을 사용할 때의 쿼리 구문에 대한 지침을 제공합니다.
가장 일반적인 사용 방식은 최상위 SELECT 문에서 사용하는 것입니다. 예를 들면 다음과 같습니다.
SELECT SingerId, SingerInfo
FROM Singers WHERE SingerID = 5
FOR UPDATE;
FOR UPDATE 절은 SELECT 문으로 조회된 데이터(여기서는 SingerID = 5)가 트랜잭션 커밋 시점에도 여전히 유효하도록 보장하여, 동시에 실행되는 다른 트랜잭션이 해당 데이터를 업데이트할 때 발생할 수 있는 정합성 문제를 방지합니다.
WITH 문에서의 사용
WITH 문의 외부 쿼리에서 FOR UPDATE 절을 지정한 경우, FOR UPDATE 절은 WITH 문 내에서 스캔된 범위를 검증하지 않습니다.
다음 쿼리에서는 FOR UPDATE 절이 공통 테이블 표현식(CTE) 쿼리로 전파되지 않기 때문에, 스캔된 범위가 검증되지 않습니다.
WITH s AS (SELECT SingerId, SingerInfo FROM Singers WHERE SingerID > 5)
SELECT * FROM s
FOR UPDATE;
CTE 쿼리 내에 FOR UPDATE 절을 지정하면, 해당 CTE 쿼리의 스캔 범위가 검증됩니다.
다음 예시에서는 SingerId > 5인 행의 SingerId 및 SingerInfo 셀이 검증됩니다.
WITH s AS
(SELECT SingerId, SingerInfo FROM Singers WHERE SingerId > 5 FOR UPDATE)
SELECT * FROM s;
서브 쿼리에서의 사용
하나 이상의 서브 쿼리가 있는 외부 수준 쿼리에서 FOR UPDATE 절을 사용할 수 있습니다. 최상위 쿼리 및 서브 쿼리 내에서 스캔된 범위는 검증되지만 표현식 서브 쿼리에서는 검증되지 않습니다.
다음 쿼리는 SingerId > 5.인 행의 SingerId 및 SingerInfo 셀을 검증합니다.
(SELECT SingerId, SingerInfo FROM Singers WHERE SingerId > 5) AS t
FOR UPDATE;
다음 쿼리는 표현식 서브 쿼리 내에 있기 때문에 Albums 테이블의 어떤 셀도 검증하지 않습니다. 표현식 서브 쿼리에서 반환된 행의 SingerId 및 SingerInfo 셀은 검증됩니다.
SELECT SingerId, SingerInfo
FROM Singers
WHERE SingerId = (SELECT SingerId FROM Albums WHERE MarketingBudget > 100000)
FOR UPDATE;
뷰를 쿼리할 때의 사용
다음 예시와 같이 FOR UPDATE 절을 사용하여 뷰를 쿼리할 수 있습니다.
CREATE VIEW SingerBio AS SELECT SingerId, FullName, SingerInfo FROM Singers;
SELECT * FROM SingerBio WHERE SingerId = 5 FOR UPDATE;
뷰를 정의할 때 FOR UPDATE 절을 사용할 수 없습니다.
지원되지 않는 사용 사례
다음 FOR UPDATE 사용 사례는 지원되지 않습니다.
- Spanner 외부 코드 실행을 위한 상호 배제 메커니즘으로 사용: Spanner의 잠금 기능을 Spanner 외부 리소스에 대한 배타적 액세스를 보장하기 위한 용도로 사용하지 마세요. 트랜잭션이 재시도되는 경우(애플리케이션 코드에서 명시적으로 또는 Spanner JDBC 드라이버와 같은 클라이언트 코드에서 암묵적으로) Spanner가 트랜잭션을 중단시킬 수 있습니다. 잠금은 커밋된 시도 동안에만 유지된다는 점이 보장됩니다.
LOCK_SCANNED_RANGES힌트와 함께 사용하는 경우:FOR UPDATE절과LOCK_SCANNED_RANGES힌트를 동일한 쿼리에서 동시에 사용할 수 없습니다. 이 둘을 함께 사용하면 Spanner에서 오류가 발생합니다. 자세한 내용은LOCK_SCANNED_RANGES힌트와의 비교를 참조하세요.- 전체 텍스트 검색 쿼리에서 사용: 전체 텍스트 검색 색인을 사용하는 쿼리에서는
FOR UPDATE절을 사용할 수 없습니다. - 읽기 전용 트랜잭션에서 사용:
FOR UPDATE절은 읽기-쓰기 트랜잭션 내에서 실행되는 쿼리에서만 유효합니다. - DDL 문 내에서 사용: 나중에 실행하기 위해 저장된 DDL 문 내의 쿼리에서는
FOR UPDATE절을 사용할 수 없습니다. 예를 들어 뷰를 정의할 때FOR UPDATE절을 사용할 수 없습니다.
다음 단계
- GoogleSQL 및 PostgreSQL에서
FOR UPDATE절을 사용하는 방법 알아보기 - 직렬화 가능한 격리에서 SELECT FOR UPDATE 사용 방법 알아보기
LOCK_SCANNED_RANGES힌트에 대해 알아보기- Spanner의 잠금에 대해 알아보기