目次 | 前の項目 | 次の項目 JDBCTM ガイド: 使用の開始


6 バッチ更新

バッチ更新機能とは、複数の更新操作文を一度にデータソースに送り、処理させることができる機能です。更新文を 1 つ 1 つ送る代わりに複数の更新文をまとめて送るようにすると、パフォーマンスが大きく向上します。バッチ更新の送信には、StatementPreparedStatementCallableStatement の各オブジェクトが使用できます。

6.1     バッチ更新

6.1.1 文

バッチ更新機能を使用すると、1 つの Statement オブジェクトで、基盤となる DBMS に、異なる一連の更新コマンドを一括して (バッチとして) 送ることができます。次の例では、新入社員を架空の会社のデータベースに追加するために必要な一連の更新操作文を、1 つのバッチとして送っています。

// turn off autocommit
con.setAutoCommit(false);

Statement stmt = con.createStatement();

stmt.addBatch("INSERT INTO employees VALUES (1000, 'Joe Jones')");
stmt.addBatch("INSERT INTO departments VALUES (260, 'Shoe')");
stmt.addBatch("INSERT INTO emp_dept VALUES (1000, 260)");

// submit a batch of update commands for execution
int[] updateCounts = stmt.executeBatch();


この例では、Statement.executeBatch() が呼び出されたときに、ドライバがトランザクションをコミットしないように、自動コミットモードを無効にしています。自動コミットを無効にすることで、エラーが発生した場合や、バッチ中の一部のコマンドの処理に失敗した場合に、トランザクションをコミットするかどうかをアプリケーション側で制御できるようになります。このような理由から、常に、バッチ更新が終了した時点で自動コミットをオフにしておくべきです。executeBatch のコミットの実装は、エラーが発生し、かつ自動コミットが true の場合に常に定義されます。

バッチ更新についての説明の普遍性を維持するため、バッチ内の各メンバのことを「要素」ということにします。これまでに見たように、バッチ内の要素は Statement オブジェクトの使用時に実行される単純なコマンドです。ここでは、Statement オブジェクトの使用方法をバッチ更新に限定していますが、以下の説明は PreparedStatment および CallableStatement オブジェクトにも当てはまります。

JDBC の新規 API には、Statement オブジェクトには、まとめて送ることができるコマンドのリスト (つまりバッチ) を管理する機能があります。Statement オブジェクトの作成時に、関連付けられたバッチは空 (つまり要素のない状態) です。呼び出し文のバッチに要素を追加するには、Statement.addBatch() メソッドを使用します。作成したコマンドのバッチを送るのを中止したい場合は、Statement.clearBatch() メソッド (上のコードにはない) を呼び出せばバッチを取り消すことができます。

実行の成功

Statement.executeBatch() メソッドを呼び出すと、基盤となるデータソースに文のバッチが送られ、実行されます。バッチの各要素は、バッチに追加された順序で逐次 (少なくとも論理的な順序で) 実行されます。バッチ内の全要素の実行が成功すると、executeBatch() はバッチ内の各要素に対し 1 つのエントリを含む整数配列を返します。配列内のエントリは、要素が処理された順序 (つまり、要素がバッチに追加された順序) に並べられます。配列内のエントリは、次の値を保持する場合があります。

  1. 配列のエントリ値がゼロ以上である場合、バッチ要素の処理が成功したことを示します。その値は、要素の実行により影響を受けたデータベース内の行数を示す更新カウントです。
  2. 値が 2 の場合、要素の処理は成功したが、影響を受けた行数は不明であることを示します。
executeBatch() を呼び出すと、Statement オブジェクトの現在の結果セットが開かれていれば、それが閉じられます。文が保持しているバッチ要素の内部リストは、executeBatch() の実行が終了すると、空の状態にリセットされます。executeQueryexecuteUpdate、または execute メソッドの動作は、文のバッチが空ではない場合に定義および実装されます。

バッチファイル内のいずれかの要素の適正な実行に失敗するか、要素が結果セットを返そうとする場合、ExecuteBatch()BatchUpdateException をスローします。バッチで実行できるのは、更新数だけを返す DLL コマンドと DML コマンドだけです。BatchUpdateException がスローされると、BatchUpdateException.getUpdateCounts() メソッドを呼び出して、バッチの実行結果を示す更新カウントの整数配列を取得できます。

実行失敗の処理

バッチファイル内のある要素が実行された場合、JDBC ドライバは残りの要素の処理を続ける場合もあれば続けない場合もあります。ただし、特定の DBMS とともに使用する場合、JDBC ドライバは常に同じ機能を提供する必要があります。たとえば、あるバッチが失敗したあと、ドライバは別のバッチの処理を継続することはできません。

最初にバッチが失敗したあとでドライバが処理を停止する場合、BatchUpdateException.getUpdateCounts() が返す配列に含まれるエントリの数は、バッチ内の要素数よりも常に少なくなります。要素は、バッチに追加された順番に実行されるため、配列に N 個の要素が含まれる場合、executeBatch() の呼び出し時に、バッチ内の最初の N 個の要素の処理が成功することを意味します。

障害が発生してもドライバが処理を継続する場合、BatchUpdateException.getUpdateCounts() が返す配列内の要素数 N は、常にバッチ内の要素数に等しくなります。BatchUpdateException がスローされてもドライバが処理を継続する場合、次の付加的な配列値が返されます。

  1. 値 -3 は、コマンドまたは要素の実行に失敗したことを示します。何らかの理由で要素を処理できなかった場合 (そのような要素は暗黙に失敗する) にも、この値が返されます。
失敗後に処理を継続しない JDBC ドライバが、更新カウントの配列内に -3 を返すことはありません。このタイプのドライバは、処理に成功した各コマンドのエントリを含むステータス配列を返すだけです。

JDBC ベースのアプリケーションは、BatchUpdateException.getUpdateCounts() が返す配列のサイズを調べることにより、失敗しても処理を継続する JDBC ドライバと、失敗後に処理を停止するドライバとを区別できます。処理を継続する JDBC ドライバは、バッチ内の各要素につき 1 つのエントリを含む配列を常に返します。失敗すると処理を停止する JDBC ドライバが返す配列内のエントリ数は、常にバッチ内の要素数よりも少なくなります。

6.1.2 PreparedStatements

バッチ内の要素は、PreparedStatement の使用時にパラメータをとるコマンドおよび関連付けられたパラメータセットで構成されます。バッチ更新機能を PreparedStatement と組み合わせて使用すると、1 つの PreparedStatement オブジェクトに複数の入力パラメータ値のセットを関連付けることができます。これにより、パラメータ値のセットを、パラメータをとる形式の更新コマンドと一緒に、基盤となる DBMS エンジンにまとめて送ることができます。

下の例では、2 人の新入社員のレコードを 1 回のバッチ処理でデータベースに追加しています。各パラメータセット (社員ごとに 1 つ) の作成は PreparedStatement.setXXX() で行い、現在のバッチへのパラメータセットの追加は PreparedStatement.addBatch() メソッドで行なっています。

// turn off autocommit
con.setAutoCommit(false);

PreparedStatement stmt = con.prepareStatement(
	"INSERT INTO employees VALUES (?, ?)");

stmt.setInt(1, 2000);
stmt.setString(2, "Kelly Kaufmann");
stmt.addBatch();

stmt.setInt(1, 3000);
stmt.setString(2, "Bill Barnes");
stmt.addBatch();
 
// submit the batch for execution
int[] updateCounts = stmt.executeBatch();


最後に、PreparedStatement.executeBatch() で更新内容を DBMS に送っています。PreparedStatement.executeBatch() を呼び出すと、文に関連付けられたバッチ要素のリストが消去されます。PreparedStatement.executeBatch() が返す配列には、Statement の場合と同様、バッチ内の各パラメータセットに対応する要素が含まれます。各要素には、更新カウントまたは「成功」を示す汎用のインジケータ (-2) のいずれかが含まれます。

PreparedStatement オブジェクトのエラー処理は、Statement オブジェクトのエラー処理と同様です。ドライバの中には、エラー発生後ただちに処理を停止するものもあれば、残りのバッチ処理を継続するものもあります。Statement の場合、BatchUpdateException.getUpdateCounts() が返す配列内の要素数を見ると、ドライバがエラー発生後にも処理を継続するかどうかがわかります。Statement の場合、同一の値を 3 つ配列要素にとることができます。配列内のエントリの順序は、要素がバッチに追加された際の順序と同じです。

6.1.3 Callable Statements

バッチ更新機能では、PreparedStatement オブジェクトと同じように CallableStatement オブジェクトも使用できます。複数の入力パラメータ値のセットを 1 つの CallableStatement に関連付け、まとめて DBMS に送ることができます。CallableStatement を使用したバッチ更新機能で呼び出されるストアドプロシージャは、更新数を返すものでなければなりません。 また、このようなストアドプロシージャでは、OUT パラメータと INOUT パラメータは使用できません。この規則に反した場合は、CallableStatement.executeBatch() は例外をスローします。エラー処理は、PreparedStatement の場合と同様です。

6.2     要件

バッチ更新のサポートはオプションです。JDBC ドライバがバッチ更新をサポートする場合、DatabaseMetaData.supportsBatchUpdates() は true を返す必要があります。サポートしない場合は false を返す必要があります。 また、下位互換性を維持するため、失敗後に処理を停止する JDBC ドライバには、値 -2 (6.1 で説明) を返すことが求められているわけではありません。ただし、値 -2 を返すことは推奨されています。処理を継続する JDBC ドライバの場合、負の戻り値を両方ともサポートする必要があります。

注: 将来、JDBC API は 6.1 で説明した負の配列エントリ値用の記号定数を定義します。これらの値は、元の JDBC 2.0 API 仕様への付録として追加されています。



目次 | 前の項目 | 次の項目
jdbc@eng.sun.com または jdbc-business@eng.sun.com
Copyright © 1996-1999 Sun Microsystems, Inc. All rights reserved.