保管点とは、データベース要求が失敗する際に DBMS によって行われた作業を取り消すメカニズムを表します。保管点はアトミックではないデータベース要求がアトミックに振る舞うようにします。実行時にエラーが発生する場合、保管点を使って保管点が開始された時点から保管点ロールバックが要求された時点までの、トランザクションによる変更を取り消すことができます。
保管点は複合 SQL ステートメントに類似しています。これにより、いくつもの SQL ステートメントを単一の実行可能なブロックにグループ化することが可能になります。そのためには、このブロックの最初のサブステートメントが実行される前に、保管点ブロックを開始するための保管点要求が必要です。サブステートメントのいずれかがエラーを起こす場合には、そのサブステートメントだけがロールバックされます。この方法では、複合 SQL ステートメントを使用するよりも細分性を図ることができます。複合 SQL ステートメントでは、 1 つのエラーによってブロック全体が終了して、複合 SQL ステートメント全体がロールバックされます。ステートメントの保管点ブロックの最後で保管点を解放するか、保管点へロールバックすることができます。
次の SQL ステートメントで保管点を作成および制御することができます。
SAVEPOINT savepoint1 ON ROLLBACK RETAIN CURSORS
RELEASE SAVEPOINT savepoint1
ROLLBACK TO SAVEPOINT
SAVEPOINT、RELEASE SAVEPOINT、および ROLLBACK TO SAVEPOINT ステートメントの完全な構文については、 SQL 解説書 を参照してください。
DB2 ユニバーサル・データベースでは、アプリケーションでの保管点の使用に関して次のような制約があります。
DB2 は保管点内に DDL ステートメントを組み込むことを可能にします。 DDL ステートメントを実行する保管点をアプリケーションが正常に解放すると、そのアプリケーションは DDL によって作成された SQL オブジェクトを継続的に使用することができます。ただし、DDL ステートメントを実行する保管点に対してアプリケーションが ROLLBACK TO SAVEPOINT ステートメントを発行すると、DB2 はこれらの DDL ステートメントの効力に依存するカーソルをすべて無効とマーク付けします。
次の例では、アプリケーションは ROLLBACK TO SAVEPOINT ステートメントを発行した後に、以前に開かれた 3 つのカーソルからフェッチすることを試みます。
SAVEPOINT savepoint_name; PREPARE s1 FROM 'sELECT FROM t1'; --issue DDL statement for t1 ALTER TABLE t1 ADD COLUMN... PREPARE s2 FROM 'sELECT FROM t2'; --issue DDL statement for t3 ALTER TABLE t3 ADD COLUMN... PREPARE s3 FROM 'sELECT FROM t3'; OPEN c1 USING s1; OPEN c2 USING s2; OPEN c3 USING s3; ROLLBACK TO SAVEPOINT FETCH c1; --invalid (SQLCODE -910) FETCH c2; --successful FETCH c3; --invalid (SQLCODE -910)
ROLLBACK TO SAVEPOINT ステートメントでは、 DB2 は "c1" および "c3" カーソルを無効としてマーク付けします。なぜなら、それらのカーソルが依存していた SQL オブジェクトが保管点内の DDL ステートメントによって操作されたからです。しかし、この例の "c2" カーソルを使用した FETCH は、 ROLLBACK TO SAVEPOINT ステートメントの後でも正常に実行されます。
無効なカーソルをクローズするには、 CLOSE ステートメントを発行します。無効なカーソルに対して FETCH を発行すると、 DB2 によって SQLCODE -910 が戻されます。無効なカーソルに対して OPEN ステートメントを発行すると、 DB2 によって SQLCODE -502 が戻されます。無効なカーソルに対して UPDATE または DELETE WHERE CURRENT OF ステートメントを発行すると、DB2 によって SQLCODE -910 が戻されます。
保管点内では、 DB2 は NOT LOGGED INITIALLY 特性を持つ表と一時表を次のように扱います。
DB2 アプリケーションのパフォーマンスを向上させるには、 INSERT BUF オプションを使用してバインドを行うことによって、アプリケーションでバッファー化挿入を使用できます。アプリケーションがバッファー化挿入および保管点の両方を利用する場合、 DB2 は SAVEPOINT、RELEASE SAVEPOINT、 OR ROLLBACK TO SAVEPOINT ステートメントを実行する前にバッファーをフラッシュします。
アプリケーション内でバッファー化挿入を使用する方法についての詳細は、 バッファー化挿入の使用を参照してください。アプリケーション・プリコンパイルおよびバインドする方法についての詳細は、 コマンド解説書 を参照してください。
アプリケーションが保管点を使用する場合、 BLOCKING NO というプリコンパイル・オプションを指定することにより、プリコンパイルまたはバインドを行うときにカーソル・ブロックを回避することを考慮してください。カーソルをブロック化すると、複数の行が事前に取り出されるのでアプリケーションのパフォーマンスは向上しますが、保管点およびブロック化カーソルを使用するアプリケーションによって戻されたデータは、データベースにコミットされたデータを反映しない場合があります。
BLOCKING NO を使用してアプリケーションをプリコンパイルしないで、 ROLLBACK TO SAVEPOINT が発生した後に FETCH ステートメントを発行する場合には、FETCH ステートメントは削除されたデータを取り出すかもしれません。たとえば、次のような SQL を含んだアプリケーションが BLOCKING NO オプションなしでプリコンパイルされたとします。
CREATE TABLE t1(c1 INTEGER); DECLARE CURSOR c1 AS 'sELECT c1 FROM t1 ORDER BY c1'; INSERT INTO t1 VALUES (1); SAVEPOINT showFetchDelete; INSERT INTO t1 VALUES (2); INSERT INTO t1 VALUES (3); OPEN CURSOR c1; FETCH c1; --get first value and cursor block ALTER TABLE t1... --add constraint ROLLBACK TO SAVEPOINT; FETCH c1; --retrieves second value from cursor block
アプリケーションが "t1" 表に対して最初の FETCH を発行すると、 DB2 サーバーは列値 (1、2、および 3) のブロックをクライアント・アプリケーションに送ります。これらの列値はクライアントによってローカルで保管されます。アプリケーションが ROLLBACK TO SAVEPOINT SQL ステートメントを発行すると、列値 '2' および '3' が表から削除されます。 ROLLBACK TO SAVEPOINT ステートメント後は、表で次の FETCH が行われると、表にその値がないとしても、列値 '2' が戻されます。アプリケーションはカーソル・ブロック化オプションを利用してパフォーマンスを向上させ、ローカルに保管したデータにアクセスするために、この値を受け取ります。
アプリケーション・プリコンパイルおよびバインドの方法についての詳細は、 コマンド解説書 を参照してください。
XA に準拠するトランザクション・マネージャーが XA_END 要求を発行する際にアプリケーションでアクティブな保管点が存在する場合には、 DB2 は RELEASE SAVEPOINT ステートメントを発行します。