明示的なトランザクション管理では、単純に一連の処理を確定するか取り消すかを決めるだけではなく、連続した処理の途中までさかのぼったり、トランザクションをネスト構造にしたりできます。
- セーブポイント -
トランザクションのロールバック(取消)は、先頭(BEGIN TRANSACTION命令を発行した位置)に戻るだけではなく、プログラマーの指定した任意の位置まで(つまり処理の途中まで)戻すことができます。
任意の位置をセーブポイントと呼び、“SAVE TRANSACTION”命令で設定します。
SAVE TRANSACTION <セーブポイント名>
とすることでこの命令を発行した場所が記録され、ROLLBACK TRANSACTION命令にこのセーブポイント名を付けて実行すれば、処理をセーブポイントの箇所までさかのぼれます。
ここで注意することは、セーブポイントにはあくまでSQL命令の実行箇所が記録されるのであって、プログラミング言語レベルでの処理の流れとは無関係だという点です。
SAVE TRANSACTION命令で記録されるのはその直後に実行されるSQL命令の直前の位置であり、ROLLBACK TRANSACTION命令にセーブポイント名を与えてさかのぼれるのは、あくまで『その間に実行されたSQL命令だけ』です。この組み合わせをforやwhileなどのループ内で実行した場合、繰り返し実行されたSQLは取り消せますが、プログラミング言語で実行した処理(例えばカウンタ変数の増減や画面の書き換えなど)は元に戻せません。
- トランザクションのネスト -
BEGIN TRANSACTION~COMMIT TRANSACTIONまたはROLLBACK TRANSACTIONによる一連のトランザクション管理はネスト(入れ子)にできます。
これは、プログラミング言語のIfのネストと同じ構造で、内側に記述された「BEGIN...~COMMIT...」または「BEGIN...~ROLLBACK...」が一対となります。
BEGIN TRANSACTION -------- (a)
:
BEGIN TRANSACTION ------ (b)
:
BEGIN TRANSACTION ---- (c)
:
COMMIT TRANSACTIONまたはROLLBACK TRANSACTION ---- (c')
:
COMMIT TRANSACTIONまたはROLLBACK TRANSACTION ------ (b')
:
COMMIT TRANSACTIONまたはROLLBACK TRANSACTION -------- (a')
上記のような構造では、(a)と(a')、(b)と(b')、(c)と(c')がそれぞれ対応します。最終的には、一番外側のトランザクション(例では(a)と(a')の構造)が完了しない限り、その内側のトランザクション管理で対象となったリソースは解放されません。
複雑なデータベース処理では、セーブポイントを使った任意箇所(トランザクション管理の実質的な開始位置以外の場所)へのロールバックや、ネストによる多重のトランザクション管理が必要な場合もあるでしょう。
しかし明示的なトランザクション管理では、あまり複雑な構想を採らない方が賢明です。複雑なSQL処理が必要な場合、当然のことながらプログラミング言語によるアプリケーションのソース自体も複雑な構造になっているはずです。それに加えてトランザクションの開始~確定または取消の処理にまで複雑な構造を持ち込むと、ソースの可読性が低下します。
トランザクションのネストはまだしも、セーブポイントによる任意箇所へのロールバックをIfやSelectなどで多重分岐している制御構造内に持ち込むと、まさにスパゲッティ状態となる危険性があります。
明示的なトランザクション管理は、できるだけシンプルな形とするのが理想です。そのためには、プログラミング言語による処理構造の設計だけではなく、最初に述べたようにシステム全体を見渡した安全で合理的なインターフェイス設計が重要になってきます。
サンプルファイル (LZH形式
20.7KB)
|
|
|