トランザクションの一時停止は、トランザクションの管理下で実行される必要のない特定の操作を、トランザクション内から実行する必要があるときに有用です。例えば、顧客がオーダーのためにトランザクションを開始し、ついでに住所を更新した場合を考えましょう。しかし、顧客の気が変わってオーダーをキャンセルしたとします。トランザクションはキャンセルされますが、住所の変更まではキャンセルしたくありません。これはトランザクションの一時停止が有用である良い例です。トランザクションの停止・再開には、三つのコマンドが使用されます:
ここでは停止されたトランザクションの必要性について考えます。請求書データベースにおいて、トランザクション中に新しい請求書番号が必要になったとします。この番号は計算され、[Settings]テーブルに保存されます。マルチユーザー環境において、並行のアクセスは保護されなければなりませんが、メインのトランザクションとは無関係なデータにも関わらず、トランザクションの影響で [Setting] テーブルが他のユーザーによってロックされてしまう可能性があります。この場合、テーブルにアクセスする際にトランザクションを停止すておくことができます。
START TRANSACTION
...
CREATE RECORD([Invoices])
[Invoices]InvoiceID:=GetInvoiceNum
...
SAVE RECORD([Invoices])
VALIDATE TRANSACTION
GetInvoiceNumメソッドは実行前にトランザクションを一時停止させます。このコードは、トランザクション外からメソッドが呼び出された場合でも動作するという点に注意して下さい:
C_LONGINT($0)
SUSPEND TRANSACTION
ALL RECORDS([Settings])
If(Locked([Settings]))
While(Locked([Settings]))
MESSAGE("Waiting for locked Settings record")
DELAY PROCESS(Current process;30)
LOAD RECORD([Settings])
End while
End if
[Settings]InvoiceNum:=[Settings]InvoiceNum+1
$0:=[Settings]InvoiceNum
SAVE RECORD([Settings])
UNLOAD RECORD([Settings])
RESUME TRANSACTION
トランザクションの停止中においては、以下の原理が採用されます:
- トランザクション中に追加または編集されたレコードにはアクセスすることができ、トランザクション中に削除されたレコードはどれも見ることができません。
- トランザクション外でレコードを作成、保存、編集することができます。
- 新規のトランザクションを開始することは可能ですが、そのトランザクション内では、停止中のトランザクションによって追加または編集されたレコードまたはレコードの値を見れません。この場合、トランザクションはそれぞれ完全に独立しており (別プロセスのトランザクションに似ています)、停止中のトランザクションはあとで再開またはキャンセル可能なことから、そこで追加あるいは編集されたレコードはどれも新規トランザクションからは自動的に非表示となります。新規トランザクションをコミットあるいはキャンセルすると、再びこれらのレコードを見ることができるようになります。
- 停止されたトランザクション内で編集、削除、または追加されたレコードは、どれも他のプロセスからはロックされたままとなります。トランザクション外から、あるいは新規トランザクション内からこれらのレコードを編集あるいは削除しようとした場合、エラーが生成されます。
これらの原理をまとめると、以下の図のようになります:
![](../../picture/2773847/pict2773847.en.png)
トランザクションAで編集された値 (レコードID1にVal11が入る) は A の "停止中" に開始された新しいトランザクションBでは利用できません。"停止中" に編集された値 (レコードID2にVal22が入り、レコードID3にはVal33が入る) はトランザクションAがキャンセルされても、保存されたままです。
エラーを管理するために、特定の機能が追加されました:
- それぞれのテーブルのカレントレコードは、トラザクション中に編集された場合には一時的にロックされ、トランザクションが再開されると自動的にロックが解除されます。この機構はトランザクションの一部で不要な保存を避けるために重要です。
- 例えばstart transaction / suspend transaction / start transaction / resume transactionのように無効なシーケンスを実行した場合には、エラーが生成されます。この機構は停止されたトランザクションを再開する際に、間に挟んだトランザクションをコミットまたはキャンセルするのを忘れるのを防ぎます。
既存の In transaction コマンドはトランザクションが開始されていれば、停止中であってもTrueを返します。カレントトランザクションが停止中であるかどうかを調べるためには、新しいTransaction activeコマンドを使用する必要があります。こちらはこういった場合にはFalseを返します。
しかし、開始されているトランザクションが存在しない場合には、どちらのコマンドも False を返します。この場合には既存の Transaction level コマンドを使用する必要があるかもしれません。こちらはこの場合に 0 (開始されているトランザクションはない) を返します。
以下の図は、様々なトランザクションのコンテキストと、トランザクションコマンドによって返される値の対応をまとめたものです: