29 ロックフリー予約の使用

この章では、データベース・アプリケーションにおけるロックフリー予約の使用方法について説明します。

トピック:

29.1 トランザクション処理での同時実行性について

通常、トランザクション処理には、古い値を新しい値に置換するデータ更新を伴うフラット・トランザクションが含まれます。ほとんどのアプリケーションでは、製品の手持数量、銀行口座残高、株式、使用可能な座席数などの数値および集計値が格納されます。このような数値集計データは、単一のエンティティとして参照されますが、1つ以上の同じデータまたは類似データに基づきます。このようなデータには、"データ←値"形式の代入ではなく、値の減算または加算が含まれます。たとえば、銀行口座残高は、口座で発生する借方と貸方トランザクションに基づきます。

在庫管理、サプライ・チェーン、金融または投資銀行、株式、旅行および娯楽を提供するアプリケーションは、数値集計データに基づいて動作します。数値集計データは一般に"ホット"リソースとして識別されます。これは、アプリケーションが継続的に、このようなデータを繰り返し読み取ったり更新するためです。このようなデータに多数のトランザクションが同時にアクセスする可能性は高いです。2フェーズ・ロック(2PL)などの従来のロック・プロトコルでは、同時トランザクションの実行は、トランザクションが行の更新を開始してロックした後にシリアライズされます。開始された更新は、トランザクションがコミットまたはロールバックでファイナライズした場合にのみ完了します。シリアル化は、行をロックしたトランザクションが完了するまで、他の同時実行トランザクションによる行へのアクセスをブロックします。同時トランザクションによるデータへのアクセスを許可する場合は、アプリケーションの正確性を維持するためにトランザクションを制御する必要があります。

マイクロサービス・アプリケーションなどの長時間実行トランザクションでは、リソースは長期間ロックされたままになり、ホット・リソースになる可能性があります。長期リソース・ロックにより、同時実行性が制限されます。旅行予約サービスなどのサービスを提供するマイクロサービス・アプリケーションでは、長時間実行トランザクションでフライト、ホテルおよび車の予約をすることがあります。このようなトランザクションは通常、Sagaとして処理され、Sagaファイナライズまでデータベースがロックされた状態で様々なサービスにまたがります。

通常の過程で同時実行性をどのように処理するかを理解するために、オンライン・ショッピング・カートの例を見てみましょう。ショッピング・カートには、販売前にカートに追加されたアイテムがあります。アプリケーションは、ユーザーが商品をカートに入れると、その商品は他の購入者が入手できなくなるが、まだ売れ残っている、というような、様々な状態での複数のトランザクションを処理できる必要があります。同時トランザクションの場合、在庫の状態および棚卸の管理は複雑になり、複数のトランザクションでカートへのアイテムの追加、カートのチェックアウトや放棄が行われます。コミットまたはロールバックで数量を変更するには、トランザクションの在庫または同類のフィールドをロックする必要があります。長期間データをロックすると、ロックが解除されるまで、他の同時トランザクションはそのアイテムにアクセスできなくなります。したがって、分離を目指し、アプリケーションでトランザクションを個別に実行できるようにすると、同時実行性が制限されます。

多くのビジネス・アプリケーションでは、"ホット"データへの同時アクセスをブロックすると、パフォーマンスに深刻な影響を及ぼし、ユーザー・エクスペリエンスとスループットが低下する可能性があります。トランザクションの原子性、一貫性および永続性の各プロパティを維持しながら、独立性を減じて同時実行性を向上させると、アプリケーションはその恩恵を受ける可能性があります。同時実行性を向上させるには、トランザクション・ライフサイクル中にホット・リソースの状態を捉えて、リソース値が変更される場合にのみデータ・ロックを有効にすることが重要です。

関連項目:

  • 予約可能列を使用してトランザクション処理の同時実行性を制御する方法の詳細は、「ロックフリー予約」を参照してください。

29.2 ロックフリー予約の用語

数値集計データ

"データ←値"形式の代入ではなく、数量(数値データ)の減算(消費、減少)または加算(補充、増加)が含まれるデータ。数値集計データの操作は、本質的に交換可能です。

ホット・データまたはホット・リソース

頻繁な読取りおよび更新が必要なトランザクションから高いトラフィックを受け取るデータまたはリソース、または長時間実行トランザクションで読取りまたは更新が行われるリソース。

トランザクション・ライフサイクル

作成からコミットまたはロールバックの状態に遷移する際のビジネス・トランザクションの状態。

補正または補正トランザクション

Sagaの一部でもある他のトランザクションのいずれかが失敗した場合、補正または補正トランザクションが、Sagaのすでにコミットされたトランザクションを補正(ロールバック)します。

予約可能

予約可能は、数値データ型の列に対して定義できる列プロパティです。予約可能列は、列に対して行われた変更のジャーナルを保持します。このようなジャーナルは、同時実行性の制御および自動補正に使用されます。

予約可能列

ホット・リソースが含まれ、ロックフリー予約で識別される列。このような列は、reservable列プロパティ・キーワードで宣言されます。

予約可能更新

予約可能列に対して行われた数値集計データの更新。

予約ジャーナル

予約ジャーナルは、ユーザー表に関連付けられた表であり、予約可能列に変更(現在の値に対するデルタ量分だけの増減)を記録します。

ロックフリー予約

予約可能更新はロックフリー予約として扱われ、対象となる行を更新するトランザクションは行をロックしませんが、予約可能列の値をデルタ量分だけ変更する意図を示すことを意味します。変更操作は、予約ジャーナルに記録されます。ロックフリー予約は、トランザクションのコミット時に実際の更新に変化します。

ロックフリー予約では、予約可能列を更新するためのコミット時にのみロックが取得されます。ロックフリー予約は、同時実行性の高いホット・データに使用され、暗黙的な補正サポートがあるため、マイクロサービス・トランザクション・モデルに適しています。

オプティミスティック・ロック

オプティミスティック・ロックは、データ・リソースのロックを取得せずにそれらのリソースをトランザクションで使用できるようにする同時実行性の制御方法です。コミットする前に、各トランザクションは、最後に読み取ったデータを他のトランザクションが変更していないことを確認します。

Saga

Sagaでは、複数の独立したマイクロサービスで構成される長時間実行ビジネス・トランザクションをカプセル化します。各マイクロサービスは、同じSagaの一部である1つ以上のローカル・トランザクションで構成されます。

29.3 ロックフリー予約

ロックフリー予約は、次の目的で、予約可能列に対して動作するトランザクションにデータベース内インフラストラクチャを提供します。

  • 予約可能列に対して行われた更新でブロックされることなく、同時トランザクションを続行できるようにします

  • 取り消されたSagaで成功したトランザクションの予約可能更新に対する自動補正を発行します

ロックフリー予約によって、アプリケーションがトランザクションに同時実行機能と自動補正機能を組み込む方法を次に示します。

予約可能列の宣言

表を作成または変更するときに、reservableキーワードを使用して予約可能列を宣言できます。ロックフリー予約は数値データ型の列に提供されます。潜在的な予約可能列を識別するには、同時実行性の向上からメリットを受ける可能性のある数値集計データが含まれるホット・リソースを探します。

トランザクション更新の予約

  • トランザクションが予約可能列に対して更新操作を発行すると、予約可能更新はロックフリー予約として予約ジャーナルに記録されます。リバース可能列に対して発行されたすべての更新は、ロックフリー予約として処理されます。

  • トランザクション更新は、行(予約可能更新がある行)をロックしませんが、行内の予約可能列をデルタ量分だけ変更(加算または減算)する意図を示します。変更量は、同じ行の予約可能列に対して以前に予約した他の未コミットの同時トランザクションを待機せずにトランザクションが続行できるように予約され確保されます。予約により、他の同時トランザクションは、同じ行に対して予約可能更新を発行できます。
  • 変更(予約可能列の現在の値に対するデルタ量分だけ増減)の操作は、予約ジャーナルに記録されます。予約可能列の実際の値を読み取ったり書き込むかわりに、トランザクションは予約可能列の値を増減する操作を発行します。予約可能列に対して行われた更新リクエストは、予約ジャーナルに記録されます。

更新の確認および遅延

トランザクションは、予約可能列に課せられた制約に基づいて、数量が更新の実行に十分かどうかを決定します。トランザクションでは、次の項目をチェックします。

  • 更新が成功することを確認します。十分な残余がある場合、予約ジャーナルの更新は続行できます。残余が更新(消費)リクエストを履行するのに十分でない場合、成功するためにアクティブな(まだコミットされていない)補充に依存せずに、予約可能列に対する更新リクエストは失敗します。
  • 予約可能列に制約または境界(CHECK制約)がないかをチェックしてビジネス・ルールを施行し、アプリケーションの正確性を保証します。CHECK制約には、予約可能列と非予約可能列のチェックを含めることができます。
  • 同時実行性を向上させるために、コミット時間まで予約可能列に対する実際の更新を遅延させます

失敗したトランザクションでの正常な更新の自動補正

ロックフリー予約では、予約可能列の状態遷移を、そのトランザクション・ライフサイクルを通じて追跡できます。残高不足やSagaの取消しなどの理由でトランザクションが取り消された場合(部分的な完了の後)、ロックフリー予約は予約可能更新の自動補正またはロールバックを発行します。

予約可能更新の永続性の確保

ロックフリー予約は、トランザクションのコミット時に実際の更新に変化します。トランザクションのロールバックにより、トランザクションが予約ジャーナルで保持するすべてのロックフリー予約が無効になります。セーブポイントにロールバックすると、影響を受けるセーブポイントの後にトランザクションによって行われたロックフリー予約が削除されます。

マイクロサービスのSagaの場合、ロックフリー予約により、取り消されたSagaで成功したローカル・トランザクションに対して実行された予約可能更新の自動補正が有効になります。ロックフリー予約は、トランザクションの実行中にデータベース内の予約可能更新を追跡できるようにし、Sagaのファイナライズまでトランザクションのコミットを超えたジャーナルを保持します。

ノート:

ロックフリー予約機能はコミット時まで行をロックしないため、自動トランザクション・ロールバック(別の23c機能)は、ロックフリー予約のみを行うトランザクションでは無処理になります。

関連項目:

29.3.1 オプティミスティック・ロックとロックフリー予約の比較

ロックフリー予約では、次のように境界内で操作することで、未処理の予約が保証されます。

  • ジャーナル処理中のリクエスト。

  • 保留中のリクエストに基づいて予測値を追跡するための新しい予約ジャーナル列を導入します。

  • 未処理の予約に基づいて新しいリクエストを許可または拒否するためにジャーナルに問い合せます。

  • 未処理の予約のため、またはリクエスト数量が使用可能数を超えている場合に、満たすことができない新しいリクエストを拒否します。

これに対して、オプティミスティック・ロックでは予約の追跡や保証はしません。

オプティミスティック・ロック手法のその他の難点を次に示します。

  • 数量が不十分なため、コミット時にリクエストが満たされない可能性があります。
  • トランザクションが最後に取り消される可能性があります。長時間実行トランザクションが取り消された場合、作業は破棄され、変更をロールバックする必要があります。

29.3.2 表作成時の予約可能列の作成

新しい表を作成するときに、reservableキーワードを使用して予約可能列を宣言できます。

  1. CREATE TABLEコマンドを変更して、次のようにロックフリー予約を有効にします。
    Create_table_command::={relational_table | object_table | XMLType_table }
    Relational_table::= CREATE TABLE [ schema. ] table …;
    relational_properties::= [ column_definition ] 
    column_definition::= column_name datatype reservable [CONSTRAINT constraint_name check_constraint]
    CREATE TABLE Account( ID NUMBER PRIMARY KEY,
     Name VARCHAR2(10),
     Balance NUMBER reservable CONSTRAINT minimum_balance CHECK (Balance >= 50))
    予約可能列"Balance"を使用して"Account"表を作成すると、関連する予約ジャーナル表が作成されます。予約ジャーナル表は、ユーザー表と同じユーザー・スキーマ下の同じ表領域に作成されます。予約ジャーナル表でも、遅延セグメント作成が有効になっています。

    ノート:

    CREATE TABLE文の構文はRESERVABLEキーワードをサポートしますが、NOT RESERVABLEキーワードはサポートしません。NOT RESERVABLEキーワードはALTER TABLEコマンドでサポートされます。

    関連項目:

    予約ジャーナル表で使用される列の詳細は、「予約ジャーナル表の列」を参照してください。

  2. ALL_CONSTRAINTSビューは、制約の詳細を取得する場合に使用します。
    SELECT table_name, constraint_name, search_condition
     FROM ALL_CONSTRAINTS
     WHERE table_name='ACCOUNT';
29.3.2.1 予約ジャーナル表の列

予約ジャーナル表には、次の列情報が含まれます。

DESCRIBE文は、前述のAccount表に関連付けられた予約ジャーナル表の列の実際の名前を示します。
SQL>desc SYS_RESERVJRNL_<object_number_of_base_table>;

表29-1 予約表の列

名前 NULLかどうか タイプ 説明:

ORA_SAGA_ID$

 

RAW(16)

トランザクションのSaga ID (saga以外のトランザクション場合は0)

ORA_TXN_ID$

 

RAW(8)

トランザクションのトランザクションID (usn、slot、seqを含む)

ORA_STATUS$

 

VARCHAR2(11)

Txn IDのステータス(値: {ACTIVE, COMMITTED, COMPENSATED})

ORA_STMT_TYPE$

 

VARCHAR2(6)

DML文タイプ{UPDATE}

ID

NOT NULL NUMBER

ユーザー表のPrimary Key

BALANCE_OP

  VARCHAR2(1)

補充または消費の'+'または'-'が指定された操作による予約可能列の操作

BALANCE_RESERVED

  NUMBER

予約可能列により予約済で、予約可能列から予約された量

29.3.3 予約可能列の追加または変更

ALTER TABLE文を変更して、予約可能列を追加したり、予約可能列を非予約可能列に変更できます。

  1. 予約可能列を追加するには、ALTER TABLEコマンドを次のように変更します。
    ALTER TABLE [ schema.]table
     [add [column_definition]]…;
     column_definition::= column_name datatype reservable [default <value>]
     [CONSTRAINT constraint_name check_constraint]
    ALTER TABLE Account
     ADD (Balance NUMBER reservable default 50 CONSTRAINT minimum_balance CHECK (Balance >= 50));
  2. 既存の列を予約可能列に変更するには、ALTER TABLEコマンドを次のように変更します。
    ALTER TABLE [ schema.]table
     [modify [column_definition]]…;
     column_definition::= column_name reservable [default <value>]
     [CONSTRAINT constraint_name check_constraint]

    既存のQOH列を予約可能列に変更し、オプションで新しい制約を追加するには、次のようにします。

    ALTER TABLE PRODUCTS 
    MODIFY (QOH reservable default 0 CONSTRAINT maxAmount CHECK (QOH <= 100));
  3. 予約可能列を非予約可能列に変更するには、ALTER TABLEコマンドを次のように変更します。
    ALTER TABLE [ schema.]table
     [modify [column_definition]]…;
     column_definition::= column_name not reservable]

    既存の予約可能列QOHを非予約可能列に変更するには、次のようにします。

    ALTER TABLE PRODUCTS modify (QOH not reservable);

    ノート:

    前述のALTER TABLEコマンドを使用して、予約可能列を非予約可能列に変換できます。予約可能列を非予約可能列に変更すると、列のロックフリー予約が無効になりますが、アプリケーションは制約の施行を選択できます。したがって、列が非予約可能列に変換されても、制約は自動的に削除されません。ALTER TABLE <table_name> DROP CONSTRAINT <constraint_name>文を使用して、制約を削除できます。

29.3.4 予約可能列のCHECK制約について

CHECK制約により、表の各行で満たす必要がある条件を指定できます。制約を満たすには、表の各行がその条件をTRUEまたは不明(NULLのため)のいずれかにする必要があります。特定の行に対するCHECK制約条件が評価される場合、条件にある列名に、その行の列値が適用されます。

ノート:

Oracleでは、CHECK制約の条件が相互に排他的かどうかは検証しません。このため、1つの列に対して複数のCHECK制約を作成する場合は、制約の用途が矛盾しないように注意する必要があります。また、条件の評価について特別な順序を想定しないでください。

予約可能列の表レベルのCHECK制約

表レベルのCHECK制約に予約可能列を設定できます。予約可能列と非予約可能列が含まれる、表レベルのCHECK制約がコミット時に検証に失敗した場合、トランザクションは取り消されます。非予約可能列の値は予約メカニズムを使用して保証できないため、取消しが発生します。

たとえば:
CREATE TABLE Account(
 ID NUMBER PRIMARY KEY,
 Name VARCHAR2(10),
 Balance NUMBER reservable,
 Earmark NUMBER,
 Limit NUMBER,
 CONSTRAINT minimum_balance CHECK (Balance + Limit – Earmark >= 0))

予約可能列を制約なしで定義することもできます。このような予約可能列では、すべてのロックフリー予約が成功します。

予約可能列では、storage句の指定はサポートされていません。

29.3.5 例: 従来のロックとロックフリー予約

次の例は、従来のロック・モードとロックフリー予約モードでの購買トランザクションを示しています。

従来のロック(長期保持ロック)

次の例では、従来のロックを使用して、50ドルの最小残高を維持しながら25ドルのアイテムの購入を許可します。

  • まず、SELECT FOR UPDATEが、残高を読み取ってロックするために発行されます。
  • 残高が75以上の場合は、アイテムの購入が許可されます。
  • 次に、UPDATEは残高を借方にします。
  • その後、トランザクションがコミットされます。
  • 残高が不足すると、トランザクションが取り消されます。
CREATE TABLE Account (
 ID NUMBER PRIMARY KEY,
 Name VARCHAR2(10),
 Balance NUMBER CONSTRAINT minimum_balance CHECK (Balance >= 50)); 

DECLARE current NUMBER;

BEGIN
 -- Read and Lock account balance
 SELECT Balance INTO current
 FROM Account
 WHERE ID = 12345 FOR UPDATE;

 IF current >= 75 THEN
  -- Sufficient funds: Perform item purchase
  PurchaseItem();
  -- Debit account balance and commit 
  UPDATE Account
  SET Balance = Balance - 25
  WHERE ID = 12345;
  COMMIT;
 ELSE
  ROLLBACK; -- Insufficient funds, so cancel
 END IF;
END;

ロックフリー予約(短期保持ロック)

次の例では、ロックフリー予約を使用して、50ドルの最小残高を維持しながら25ドルのアイテムの購入を許可します。予約可能列の制約により、行をロックせずに列値に予約を入れることができます。

  • 残高更新では、アカウントをロックせずに25ドルが予約されます。
  • 予約が成功すると、アイテムの購入を続行できます。
  • 最終コミットでは、アカウント行がロックされ、予約に記録された25ドルの残高借方が適用されます。
  • 資金不足のために予約が失敗した場合、update文はCHECK制約違反で失敗します。
CREATE Table Account(
 ID NUMBER PRIMARY KEY,
 Name VARCHAR2(10),
 Balance NUMBER RESERVABLE CONSTRAINT minimum_balance CHECK (Balance >= 50));

BEGIN
 -- Reserve 25 from account balance
 UPDATE Account SET Balance = Balance - 25
 WHERE ID = 12345;
 -- If reservation succeeds perform item purchase
 PurchaseItem();
 -- The commit finalizes the balance update
 COMMIT; -- This gets the account row lock 
 EXCEPTION WHEN Check_Constraint_Violated
 -- This indicates that the reservation failed
 THEN ROLLBACK;
END;

29.3.6 予約可能列ビューの問合せ

予約可能列のディクショナリ・ビューに対して問合せを実行して、予約可能列に関する情報を取得できます。

DBA_TAB_COLUMNSUSER_TAB_COLUMNSおよびALL_TAB_COLUMNSビューに対して問合せを実行して、列が予約可能列として宣言されているかどうかを確認できます。
SELECT table_name, column_name , reservable_column
 FROM user_tab_columns
 WHERE table_name = <table name>;
DBA_TAB_COLSUSER_TAB_COLSおよびALL_TAB_COLSビューに対して問合せを実行して、列が予約可能列として宣言されているかどうかを確認できます。
SELECT table_name, column_name , reservable_column 
 FROM user_tab_cols 
 WHERE table_name = <table name>;
問合せの例:
SQL> SELECT table_name, column_name , reservable_column 
 FROM user_tab_cols 
 WHERE table_name = 'ACCOUNT';
結果:
TABLE_NAME     COLUMN_NAME    RES
–-----------------------------------
ACCOUNT         NAME          NO
ACCOUNT         BALANCE       YES
ACCOUNT         ID            NO

3 rows selected
DBA_TABLESUSER_TABLESおよびALL_TABLESビューに対して問合せを実行して、ユーザー表に1つ以上の予約可能列があるかどうかを確認できます。
SELECT table_name, has_reservable_column 
 FROM user_tables 
 WHERE table_name = <table name>;
問合せの例:
SQL> SELECT table_name, has_reservable_column 
 FROM user_tables 
 WHERE table_name = 'ACCOUNT';
結果:
TABLE_NAME     HAS
–-------------------
ACCOUNT        YES

1 row selected

29.4 ロックフリー予約を使用するメリット

ユーザー・エクスペリエンスおよび同時実行性の向上

ロックフリー予約では、ホット・データのロックを短い時間間隔で保持するため、ユーザー・エクスペリエンスと同時実行性が向上します。トランザクションは、ロックせずに予約可能列値から数量を予約します。ロックが実行されるのは、トランザクションのコミット中に値が変更されるときのみです。

自動補正

補正機能を使用する場合は、データベースを一貫した状態に遷移できるように依存性を追跡する必要があります。Sagaの場合、これらの依存性は長期間(変更が確定されるまで)追跡する必要があります。Saga実装でロックフリー予約を使用できます。ロックフリー予約では、Sagaトランザクションが取り消された場合、すでにコミットされているSagaの他のトランザクションのロールバックを処理するために暗黙的な補正トランザクションが自動的に発行されます。複雑な補正機能を記述する必要はありません。ロックフリー予約により、ジャーナルによる自動補正が可能になり、失敗したSagaの正常な更新を元に戻すことができます。

効率的なリソース使用率

ロックフリー予約を使用すると、複数のトランザクションをパラレルで実行でき、相互にブロックせずにリソースを使用できます。リソース使用率の効率化は、待機時間とレスポンス時間を短縮することで改善されます。

幅広い範囲

予約可能更新は数値集計データに対して実行されます。これは、多種多様なデータに作用する多くのアプリケーションに不可欠です。ロックフリー予約を使用した同時実行性の向上は、予約可能更新を含む行の割合が高い場合に、アプリケーションにメリットをもたらします。長時間実行トランザクションに予約可能更新があるアプリケーションは、トランザクションにおける同時実行性の改善から最も恩恵を受ける可能性があります。これらのアプリケーションには、銀行業務、在庫管理、発券業務およびイベント予約を処理するアプリケーションが挙げられます。

29.5 ロックフリー予約のガイドラインと制限事項

この項では、ロックフリー予約のガイドラインと制限事項について説明します。

29.5.1 予約可能列のガイドラインと制限事項

ロックフリー予約を使用する場合、予約可能列と予約可能列を持つユーザー表については、次のガイドラインに従ってください。

  • ユーザー表のスキーマ定義では、reservableキーワードを使用して予約可能列を宣言します。予約可能列はロックフリー予約を提供します。

  • 予約可能列は、Oracle数値データ型(NUMBERINTEGERおよびFLOAT)の列に対してのみ指定できます。

  • 予約可能列は集計タイプであるため、予約可能列をPrimary Keyまたはアイデンティティ列(または仮想列)にすることはできません。

  • ユーザー表には最大10個の予約可能列を含めることができます。

  • 予約可能列が含まれるユーザー表には、Primary Keyが必要です。

  • 予約可能列では、索引はサポートされていません。

  • 複合予約可能列は使用できません。

  • ブロック・チェーン表およびシャード表では、予約可能列は使用できません。

  • 予約可能列はCHECK制約式にのみ含めることができます。CHECK制約は、列レベルまたは表レベルに指定できます。ユーザー定義の操作上の制約は、アプリケーションの正確性を保証するために、予約可能列に使用されます。

    • オプションのCHECK制約を、予約可能列に指定できます。

    • 予約可能列は他のタイプの制約に含めることはできません。予約可能列を含むCHECK以外の制約は使用できません。予約可能列を外部キー制約に含めることはできません。

  • 外部表、クラスタ表、IOT表および一時表には予約可能列を指定できません。

  • 予約可能列では、パーティション化を実行できません。

  • 予約可能列が含まれるユーザー表には、2フェーズのオンラインDDL最適化は提供されません。

  • ユーザー表から予約可能列を削除すると、対応するロックフリー予約追跡列が予約ジャーナル表から削除されます。最後の予約可能列がユーザー表から削除されると、予約ジャーナル表は削除されます。予約可能列を削除したり、列をUNUSEDとマークするには、保留中の予約があるトランザクションをファイナライズする必要があります。

29.5.2 update文のガイドラインおよび制限事項

ロックフリー予約を使用する場合は、次に示すUPDATE文のガイドラインに従ってください。

  • 予約可能列に対する更新は、次のいずれかとして指定する必要があります。

    UPDATE <table_name> 
    SET <reservable_column_name> = <reservable_column_name> + (<expression>)
    WHERE <primary_key_column> = <expression>
    UPDATE <table_name>
    SET <reservable_column_name> = <reservable_column_name> - (<expression>)
    WHERE <primary_key_column> = <expression>

    ノート:

    SET <reservable_column_name> = <value>は使用できません。直接値を割り当てると、エラーが発生します。

    ノート:

    複合主キーの場合、すべての主キー列は、予約可能更新のWHERE句で指定する必要があります。
  • 1つのupdate文で、表の複数の予約可能列を更新できます。

  • 同じ更新文に予約可能列の更新と非予約可能列の更新を混在させることはできません。また、予約可能な列更新文では、DML returning句はサポートされていません。

  • 予約可能列に対する更新は、トランザクションのコミットまで行をロックしません。かわりに、予約可能列はロックフリー予約を提供します。ロックフリー予約では、他の同時トランザクションがブロックされることなく、予約可能列を更新できます。

  • ロックされた(行の非予約可能列を更新したものと同じトランザクションまたは別のトランザクションによってロックされた)行で発行された予約可能更新では、ロックフリー予約を取得できます。

  • 予約可能列の保留中の予約に変換される更新により、保留中の予約を考慮した後、予約可能列の制約に違反していないことが保証されます。

  • トランザクションは、トランザクションが予約可能更新を発行した(ユーザー表に関連付けられている)予約ジャーナル表から選択することで、独自のロックフリー予約を読み取ることができます。他のトランザクションによって行われた予約は表示されません。

29.5.3 挿入および削除のガイドライン

ロックフリー予約を使用する場合、予約可能列がある表に発行されるINSERT文とDELETE文については、次のガイドラインに従ってください。

  • トランザクションは、動作を変更せずに、予約可能列の値が含まれる行全体を挿入できます。

  • 挿入トランザクションがコミットされるまで、挿入された行は、予約可能更新の他のトランザクションには表示されません。

  • 削除するユーザー表の行について保留中の予約があるときにDELETE文が発行された場合、削除を続行するには、それらの行に対するアクティブなロックフリー予約が含まれるトランザクションが完了する必要があります。DELETE文は、内部的に5秒間隔で再試行され、影響を受ける行について保留中の予約がなくなると許可されます。タイムアウト期間後、DELETE文を続行できなかった場合は、リソース・ビジー・メッセージを含むエラーが発生します。DELETE文は後で発行できます。

29.5.4 同時DDL文のガイドライン

ロックフリー予約を使用する場合、予約可能列がある表に発行される同時DDL文については、次のガイドラインに従ってください。

  • 予約可能列が含まれる表に対してDDL文が進行中の場合、DDLが完了するまで、ユーザー表に対して予約可能更新は実行できません。

  • ユーザー表の任意の行に対して保留中の予約があるときにDDL文が発行された場合、そのDDL文はアクティブな予約を持つトランザクションが完了するまでブロックされます。

29.5.5 予約ジャーナル表の制限事項

予約ジャーナル表の、次の制限事項に従ってください。

ユーザーDMLおよびDDL操作は、予約ジャーナル表では許可されません。DMLを使用して予約ジャーナル表を作成または変更することはできません。SQLを使用して、予約表の定義を削除、切捨て、名前変更または変更することはできません。