TROLLBACK (ObjectScript)
構文
TROLLBACK:pc
TRO:pc
TROLLBACK:pc 1
TRO:pc 1
引数
引数 | 説明 |
---|---|
pc | オプション — 後置条件式 |
1 | オプション — 整数 1。1 レベルの入れ子のロールバック。リテラルとして指定する必要があります。 |
説明
TROLLBACK は現在のトランザクションを終了し、ジャーナルされたすべてのデータベース値を、トランザクションの開始時に保持されていた値にリストアします。TROLLBACK には、以下の 2 つの形式があります。
-
TROLLBACK は、TSTART が発行されているレベル数に関係なく、処理中のすべてのトランザクションをロールバックし、$TLEVEL を 0 にリセットします。
-
TROLLBACK 1 は、入れ子になったトランザクションの現在のレベル (最新の TSTART によって開始されたレベル) をロールバックし、$TLEVEL を 1 つデクリメントします。この 1 という引数は、リテラル値の 1 でなければならず、1 に解決される変数や式にすることはできません。1 以外の数字はサポートされていません。
$TLEVEL 特殊変数から、入れ子になったトランザクションのレベルを決定できます。$TLEVEL が 0 に設定されるときに呼び出される TROLLBACK は、何も影響を与えません。
%SYS.Journal.SystemOpens in a new tab クラスの GetImageJournalInfo()Opens in a new tab メソッドを使用して、ジャーナル・ファイル内で TSTART コマンドを検索し、開いているトランザクションを特定できます。TSTART は $TLEVEL をインクリメントし、ジャーナル・ファイル・レコードに書き込みます。その場合、$TLEVEL が 0 であれば、“BT” (Begin Transaction) レコードが、$TLEVEL が 0 よりも大きければ、“BTL” (Begin Transaction with Level) レコードが書き込まれます。%SYS.Journal.SystemOpens in a new tab クラスの Sync()Opens in a new tab メソッドを使用して、成功したロールバック処理の後のジャーナル・バッファをフラッシュします。
TROLLBACK は、ロールバック処理の間、Ctrl-C による割り込みを無効にします。
ロールバックの対象
TROLLBACK は、ジャーナルされたすべてのオペレーションをロールバックします。そのため、トランザクション内で加えられた変更に以下のような影響があります。
-
TROLLBACK は、SET オペレーションや KILL オペレーションを含め、グローバル変数に対する大半の変更をロールバックします。例外は次のリストに示します。
Note:既定では、グローバル変数の SET または KILL は、他のプロセス (トランザクションの外部で実行されている可能性あり) から即座に確認できます。グローバル変数の SET または KILL が、他のプロセスから見られないようにするには、LOCK コマンドを使用してグローバル変数へのアクセスを調整する必要があります。
-
TROLLBACK は、トランザクション中の変更をグローバル変数のビット文字列値にロールバックします。ただし、グローバル変数のビット文字列は、ロールバック操作によって以前の内部文字列表現に戻りません。
-
TROLLBACK は、挿入、更新、および削除の変更を SQL データにロールバックします。
ただし、アプリケーションによって行われたすべての変更がジャーナルされるわけではないため、TROLLBACK は、トランザクション内で実行される場合であっても、以下の変更はロールバックしません。
-
ローカル変数またはプロセス・プライベート・グローバルに対する変更
-
特殊変数 ($TEST など) に対する変更
-
現在のネームスペースに対する変更
-
LOCK コマンドによるロックまたはアンロック・オペレーション
-
グローバル変数に対する $INCREMENT の変更
-
グローバル変数に対する $SEQUENCE の変更
-
外部からデータベースに加えられた変更
トランザクション・ロールバックのロギング
ロールバック処理中にエラーが発生した場合は、<ROLLFAIL> エラー・メッセージが発行され、messages.log オペレータ・メッセージ・ログ・ファイルにエラー・メッセージが記録されます。管理ポータルの [システムオペレーション] オプションを使用して、messages.log を表示できます ([システムオペレーション]、[システムログ]、[メッセージログ])。
既定では、messages.log オペレータ・メッセージ・ログ・ファイルは、InterSystems IRIS システム管理ディレクトリ (mgr) にあります。この既定の場所は構成可能です。管理ポータルの [システム管理] オプションに移動して、[構成]、[追加の設定]、[メモリ詳細] の順に選択します。[ConsoleFile] の現在の設定を表示して編集します。既定では、この設定は空白で、コンソール・メッセージは mgr ディレクトリの messages.log に転送されます。messages.log に異なるディレクトリの場所を指定することもできます。
<ROLLFAIL> エラー
TROLLBACK がトランザクションを正常にロールバックできない場合、<ROLLFAIL> エラーが発生します。このプロセスの動作は、システム全体のジャーナル構成設定フラグ [エラー発生時に凍結する] (管理ポータルから、[システム管理]、[構成]、[システム構成]、[ジャーナル設定] の順に選択) の設定に応じて以下のように異なります。
-
[エラーの発生時に凍結する] が設定されていない場合 (既定)、プロセスは <ROLLFAIL> エラーを受け取ります。トランザクションは閉じられ、そのトランザクションに対して保持されているすべてのロックが解除されます。このオプションでは、データ整合性よりシステムの可用性が優先されます。
-
[エラーの発生時に凍結する] が設定されている場合、プロセスは停止し、ジョブ削除デーモン (CLNDMN) が、開いているトランザクションのロールバックを再試行します。CLNDMN が再試行している間、トランザクションに対して保持されているロックは変更されませんが、システムは停止する場合があります。このオプションでは、システムの可用性よりデータ整合性が優先されます。
詳細は、"データ整合性ガイド" の "ジャーナル入出力エラー" を参照してください。
<ROLLFAIL> が発生する場合、%msg は、<ROLLFAIL> エラーそのものと、ロールバックを発生させた直前のエラーを記録します。例えば、日付を範囲外の値で更新しようとしてロールバックに失敗すると、以下の %msg が返されます。SQLCODE = -105 %msg = Unexpected error occurred: <ROLLFAIL>%0Ac+1^dpv during TROLLBACK.Previous error: SQLCODE=-105, %msg='Field 'Sample.Person.DOB' (value '5888326') failed validation'.
<ROLLFAIL> は、トランザクション内で、グローバルがリモート・データベースにアクセスした後、プログラムが明示的にそのリモート・データベースをディスマウントした場合のトランザクション・ロールバック時に発生します。
<ROLLFAIL> は、データベース変更を行う前にプロセスがジャーナリングを無効にして、トランザクション・ロールバックを起動したエラーが発生した場合のトランザクション・ロールバック時に発生します。<ROLLFAIL> は、すべてのデータベース変更が行われた後、TROLLBACK コマンドを発行する前にプロセスがジャーナリングを無効にした場合のトランザクション・ロールバック時には発生しません。その代わりに、InterSystems IRIS は、ロールバック処理中にジャーナリングを一時的に有効にします。ロールバック処理の完了時に、InterSystems IRIS はジャーナリングを再び無効にします。
一時停止されたトランザクション
%SYSTEM.ProcessOpens in a new tab クラスの TransactionsSuspended()Opens in a new tab メソッドを使用して、プロセスの現在のすべてのトランザクションを一時停止および再開することができます。トランザクションを一時停止すると、変更のジャーナリングが一時停止されます。したがって、現在のトランザクション中にトランザクションの一時停止が発生した場合、トランザクションが一時停止されているときに行われた変更は、TROLLBACK によってロールバックできません。ただし、TROLLBACK は、トランザクションの一時停止が有効になる前または後に発生した、現在のトランザクション中に行われたすべての変更をロールバックします。
詳細は、"トランザクション処理での ObjectScript の使用法" を参照してください。
SQL とトランザクション
ObjectScript と SQL のトランザクション・コマンドは完全に互換性があり、置き換え可能ですが、以下の例外があります。
ObjectScript TSTART と SQL START TRANSACTION はどちらも、トランザクションが進行中でない場合にトランザクションを開始します。ただし、START TRANSACTION では、入れ子になったトランザクションはサポートされません。そのため、入れ子になったトランザクションが必要な場合 (または必要になる可能性がある場合) には、トランザクションを TSTART で始めることをお勧めします。SQL 標準との互換性が必要な場合は、START TRANSACTION を使用してください。
ObjectScript トランザクション処理は、入れ子になったトランザクションを限定的にサポートします。SQL トランザクション処理はトランザクション内のセーブポイントをサポートします。
クエリ・キャッシュの削除
トランザクションの際に %SYSTEM.SQLOpens in a new tab クラスの Purge()Opens in a new tab メソッドを呼び出してクエリ・キャッシュを削除すると、クエリ・キャッシュは永久に削除されます。後続の TROLLBACK では、削除されたクエリ・キャッシュはリストアされません。
グローバルと TROLLBACK 1
TROLLBACK 1 は、入れ子になったトランザクション内で変更されたすべてのグローバルをロールバックしてリストアします。ただし、入れ子のトランザクションをサポートしないリモート・システムにマップされたグローバルが変更された場合、その変更は入れ子の最も外側で生じたものとして処理されます。こうしたグローバルは、TROLLBACK が呼び出されるか、または $TLEVEL が 1 のときに TROLLBACK 1 が呼び出されることで、$TLEVEL が 0 にリセットされたときにのみロールバックされます。
ロックと TROLLBACK 1
TROLLBACK 1 は、入れ子になったトランザクションの実行中に設定されたロックを以前の状態にリストアしません。トランザクションの実行中に設定されたすべてのロックは、レベル 0 へのTROLLBACK または TCOMMIT によってトランザクションが終了するまで、ロック・テーブルに残ります。その時点で、InterSystems IRIS は入れ子になったトランザクションの実行中に作成されたすべてのロックを解放し、既存のすべてのロックを TSTART より前の状態にリストアします。
入れ子になったトランザクションの TCOMMIT は対応するロックを解除しないため、次の TROLLBACK はコミットされたサブトランザクション内でロックを実行する場合があります。
引数
pc
オプションの後置条件式です。InterSystems IRIS は、後置条件式が True (0 以外の数値に評価される) の場合にコマンドを実行します。InterSystems IRIS は、後置条件式が False (0 に評価される) の場合はコマンドを実行しません。詳細は、"コマンド後置条件式" を参照してください。
例
以下の例では、口座間でランダムな金額を送金する、単一レベルのトランザクションを使用しています。送金額が利用可能な残高を超えている場合、プログラムは TROLLBACK を使用して以下のようにトランザクションをロールバックします。
SetupBankAccounts
SET num=12345
SET ^CHECKING(num,"balance")=500.99
SET ^SAVINGS(num,"balance")=100.22
IF $DATA(^NumberOfTransfers)=0 {SET ^NumberOfTransfers=0}
BankTransfer
WRITE "Before transfer:",!,"Checking=$",^CHECKING(num,"balance")," Savings=$",^SAVINGS(num,"balance"),!
// Transfer funds from one account to another
SET transfer=$RANDOM(1000)
WRITE "transfer amount $",transfer,!
DO CkToSav(num,transfer)
IF ok=1 {WRITE "sucessful transfer",!,"Number of transfers to date=",^NumberOfTransfers,!}
ELSE {WRITE "*** INSUFFICIENT FUNDS ***",!}
WRITE "After transfer:",!,"Checking=$",^CHECKING(num,"balance")," Savings=$",^SAVINGS(num,"balance"),!
RETURN
CkToSav(acct,amt)
TSTART
SET ^CHECKING(acct,"balance") = ^CHECKING(acct,"balance") - amt
SET ^SAVINGS(acct,"balance") = ^SAVINGS(acct,"balance") + amt
SET ^NumberOfTransfers=^NumberOfTransfers + 1
IF ^CHECKING(acct,"balance") > 0 {TCOMMIT SET ok=1 QUIT:ok}
ELSE {TROLLBACK SET ok=0 QUIT:ok}
以下の例では、入れ子になったトランザクションでの TROLLBACK の影響を示します。各 TSTART は $TLEVEL をインクリメントし、グローバルを設定します。内側の入れ子になったトランザクションで TCOMMIT を発行すると、$TLEVEL がデクリメントされますが、入れ子になったトランザクションでの変更のコミットは延期されます。この場合、外側のトランザクションにある後続の TROLLBACK により、すべての変更がロールバックされます。このロールバックには、内側の"コミット済みの" 入れ子になったトランザクションで行われた変更も含まれます。
SET ^a(1)="[- - -]",^b(1)="[- - -]"
WRITE !,"level:",$TLEVEL," ",^a(1)," ",^b(1)
TSTART
LOCK +^a(1)
SET ^a(1)="hello"
WRITE !,"level:",$TLEVEL," ",^a(1)," ",^b(1)
TSTART
LOCK +^b(1)
SET ^b(1)="world"
WRITE !,"level:",$TLEVEL," ",^a(1)," ",^b(1)
TCOMMIT
WRITE !,"After TCOMMIT"
WRITE !,"level:",$TLEVEL," ",^a(1)," ",^b(1)
TROLLBACK
WRITE !,"After TROLLBACK"
WRITE !,"level:",$TLEVEL," ",^a(1)," ",^b(1)
QUIT
以下の例では、TROLLBACK によってグローバル変数がロールバックされながら、ローカル変数がロールバックされないことを示します。
SET x="default",^y="default"
WRITE !,"level:",$TLEVEL
WRITE !,"local:",x," global:",^y
TSTART
SET x="first",^y="first"
WRITE !,"TSTART level:",$TLEVEL
WRITE !,"local:",x," global:",^y
TSTART
SET x=x_" second",^y=^y_" second"
WRITE !,"TSTART level:",$TLEVEL
WRITE !,"local:",x," global:",^y
TSTART
SET x=x_" third",^y=^y_" third"
WRITE !,"TSTART level:",$TLEVEL
WRITE !,"local:",x," global:",^y
TROLLBACK
WRITE !!,"After Rollback:"
WRITE !,"TROLLBACK level:",$TLEVEL
WRITE !,"local:",x," global:",^y
以下の例では、グローバルに対する $INCREMENT 変更がロールバックされないことを示します。
SET ^x=-1,^y=0
WRITE !,"level:",$TLEVEL
WRITE !,"Increment:",$INCREMENT(^x)," Add:",^y
TSTART
SET ^y=^y+1
WRITE !,"level:",$TLEVEL
WRITE !,"Increment:",$INCREMENT(^x)," Add:",^y
TSTART
SET ^y=^y+1,^z=^z_" second"
WRITE !,"level:",$TLEVEL
WRITE !,"Increment:",$INCREMENT(^x)," Add:",^y
TSTART
SET ^y=^y+1,^z=^z_" third"
WRITE !,"level:",$TLEVEL
WRITE !,"Increment:",$INCREMENT(^x)," Add:",^y
TROLLBACK
WRITE !!,"After Rollback"
WRITE !,"level:",$TLEVEL
WRITE !,"Increment:",^x," Add:",^y