このページでは、反復可能読み取り分離で FOR UPDATE
句を使用する方法について説明します。
FOR UPDATE
句のロック メカニズムは、繰り返し可能な読み取りとシリアル化可能な分離で異なります。直列化可能分離とは異なり、Repeatable Read 分離では 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
句は、トランザクションが commit されるときに 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
句は、1 つ以上のサブクエリを含む外側レベルのクエリで使用できます。最上位クエリとサブクエリ内でスキャンされた範囲は、式サブクエリを除き、検証されます。
次のクエリは、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 によって中断される場合があります。たとえば、トランザクションが再試行された場合、アプリケーション コードによって明示的に試行されたか、Spanner JDBC ドライバなどのクライアント コードによって暗黙に試行されたかにかかわらず、トランザクションの試行が実際に行われている間にロックが実施されたことのみが保証されます。
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 のロックについて学習する。