JDBC アプリケーションでのバッチ更新の作成

表の各行を 1 行ずつ更新する代わりにバッチ更新を使用すれば、JDBC によって一群の更新を同時に実行できます。 同じバッチ更新に組み込めるステートメントのことをバッチ可能 ステートメントといいます。

このタスクについて

入力パラメーターまたはホスト式が含まれているステートメントをバッチに組み込めるのは、そのバッチが同じステートメントの他のインスタンスだけで構成されている場合に限られます。 このタイプのバッチのことを同種バッチ といいます。 入力パラメーターのないステートメントをバッチに組み込めるのは、そのバッチに含まれている他のステートメントにも入力パラメーターやホスト式がない場合に限られます。 このタイプのバッチのことを異種バッチ といいます。 2 つのステートメントを同じバッチに組み込める場合、それらのステートメントはバッチ互換 であるといいます。

SQL バッチ更新の作成、実行、除去には、以下の Statement メソッドを使用します。
  • addBatch
  • executeBatch
  • clearBatch

以下の PreparedStatement メソッドと CallableStatement メソッドを使用してパラメーターのバッチを作成すれば、1 つのステートメントをバッチの中で複数回実行し、各実行時に別々のパラメーター・セットを適用する、という操作を実行できます。

  • addBatch
バッチの中でステートメントを実行するときの制限:
  • バッチの中で SELECT ステートメントを実行しようとすると、BatchUpdateException がスローされます。
  • バッチの中で実行する CallableStatement オブジェクトには、出力パラメーターを組み込めます。 ただし、出力パラメーターの値を取得することはできません。 そうしようとすると、BatchUpdateException がスローされます。
  • バッチの中で実行する CallableStatement オブジェクトから ResultSet オブジェクトを取得することはできません。 BatchUpdateException はスローされませんが、getResultSet メソッド呼び出しでは NULL 値が返されます。

プロシージャー

バッチ更新を実行するには、以下に示す各ステップ群のうち、いずれか 1 つを実行します。

  • 入力パラメーターのない複数のステートメントを使用するバッチ更新を作成するには、以下の基本手順を実行します。
    1. バッチの中で実行する各 SQL ステートメントごとに、addBatch メソッドを呼び出します。
    2. executeBatch メソッドを呼び出して、ステートメントのバッチを実行します。
    3. エラーを確認します。 エラーがなければ、以下のようにします。
      1. executeBatch の呼び出しで返された配列から、各 SQL ステートメントで更新された行の数を取得します。 この数には、トリガーで更新された行や参照整合性の適用によって更新された行は含めません。
      2. AutoCommitConnection オブジェクトに対して無効になっている場合は、 commit メソッドを呼び出して変更をコミットします。

        AutoCommitConnection オブジェクトに対して有効になっている場合、 IBM® Data Server Driver for JDBC and SQLJ バッチの最後に commit メソッドが追加されます。

  • 1 つのステートメントで複数の入力パラメーター・セットを使用するバッチ更新を作成するには、以下の基本手順を実行します。
    1. バッチ・ステートメントが検索 UPDATE、検索 DELETE、または MERGE ステートメントの場合は、接続の自動コミット・モードを false に設定します。
    2. prepareStatement メソッドを呼び出して、PreparedStatement オブジェクトを作成します。
    3. 入力パラメーター値の各セットごとに、以下のようにします。
      1. setXXX メソッドを実行して、入力パラメーターに値を割り当てます。
      2. addBatch メソッドを呼び出して、入力パラメーターのセットをバッチに追加します。
    4. executeBatch メソッドを呼び出して、すべてのパラメーター・セットでステートメントを実行します。
    5. エラーがなければ、以下のようにします。
      1. executeBatch の呼び出しで返された配列から、SQL ステートメントのそれぞれの実行で更新された行の数を取得します。 この更新行数には、トリガーで更新された行や参照整合性の適用によって更新された行は含まれません。

        以下の条件が真である場合、 IBM Data Server Driver for JDBC and SQLJ 各 SQL 文で影響を受けた行の数ではなく、 Statement.SUCCESS_NO_INFO (-2) が返されます

        • アプリケーションは、 Db2 for z/OS® バージョン8の新機能モード、またはそれ以降です。
        • アプリケーションは、 3.1 バージョン以降を使用しています。 IBM Data Server Driver for JDBC and SQLJ
        • これは、 IBM Data Server Driver for JDBC and SQLJ 複数行のINSERT操作を使用して、バッチ更新を実行します。

        これが生じるのは、複数行 INSERT を使用すると、データベース・サーバーがバッチ全体を 1 つの操作として実行するので、個々の SQL ステートメントの結果が戻されないためです。

      2. AutoCommitConnection オブジェクトに対して無効になっている場合は、 commit メソッドを呼び出して変更をコミットします。

        AutoCommitConnection オブジェクトに対して有効になっている場合、 IBM Data Server Driver for JDBC and SQLJ バッチの最後に commit メソッドが追加されます。

      3. PreparedStatement オブジェクトから自動生成キーが返される場合、DB2PreparedStatement.getDBGeneratedKeys を呼び出して、それらの自動生成キーを含む ResultSet オブジェクトの配列を取得します。

        返された配列の長さをチェックします。 返された配列の長さが 0 なら、自動生成キー取得時にエラーが発生しています。

    6. エラーが発生した場合は、BatchUpdateException を処理します。

以下のコード断片では、2 つのパラメーター・セットをバッチの中に組み込みます。 1 つの UPDATE ステートメントを 2 つの入力パラメーター・セットのそれぞれに基づいて 2 回実行します。 選択されたステートメントの右にある番号は、前述のステップに対応しています。

try {
…
  PreparedStatement preps = conn.prepareStatement(    
    "UPDATE DEPT SET MGRNO=? WHERE DEPTNO=?");           2 
  ps.setString(1,mgrnum1);                               3a 
  ps.setString(2,deptnum1);
  ps.addBatch();                                         3b 

  ps.setString(1,mgrnum2);
  ps.setString(2,deptnum2);
  ps.addBatch();
  int [] numUpdates=ps.executeBatch();                   4 
  for (int i=0; i < numUpdates.length; i++) {            5a 
    if (numUpdates[i] == SUCCESS_NO_INFO)
      System.out.println("Execution " + i + 
        ": unknown number of rows updated");
    else
      System.out.println("Execution " + i + 
        "successful: " numUpdates[i] + " rows updated");
  }
  conn.commit();                                         5b 
} catch(BatchUpdateException b) {                        6 
  // process BatchUpdateException
}

以下のコード断片では、バッチ INSERT ステートメントにより自動生成キーが返されます。

import java.sql.*;
import com.ibm.db2.jcc.*;
…
Connection conn;
…
try {
…
  PreparedStatement ps = conn.prepareStatement(          2 
    "INSERT INTO DEPT (DEPTNO, DEPTNAME, ADMRDEPT) " +
    "VALUES (?,?,?)",
    Statement.RETURN_GENERATED_KEYS);
  ps.setString(1,"X01");                                 3a 
  ps.setString(2,"Finance");
  ps.setString(3,"A00");
  ps.addBatch();                                         3b 
  ps.setString(1,"Y01");                          
  ps.setString(2,"Accounting");
  ps.setString(3,"A00");
  ps.addBatch();                                  

  int [] numUpdates=preps.executeBatch();                4 

  for (int i=0; i < numUpdates.length; i++) {            5a 
    if (numUpdates[i] == SUCCESS_NO_INFO)
      System.out.println("Execution " + i + 
        ": unknown number of rows updated");
    else
      System.out.println("Execution " + i + 
        "successful: " numUpdates[i] + " rows updated");
  }
  conn.commit();                                         5b 
  ResultSet[] resultList = 
    ((DB2PreparedStatement)ps).getDBGeneratedKeys();     5c 
  if (resultList.length != 0) {
    for (i = 0; i < resultList.length; i++) {
        while (resultList[i].next()) {
          java.math.BigDecimal idColVar = rs.getBigDecimal(1);
                              // Get automatically generated key
                              // value
          System.out.println("Automatically generated key value = " 
            + idColVar);
        }
    }
  }
  else {
    System.out.println("Error retrieving automatically generated keys");
  }
} catch(BatchUpdateException b) {                        6 
  // process BatchUpdateException
}

以下のコード断片では、バッチ UPDATE ステートメントにより自動生成キーが返されます。 このコードでは、DEPTNO 列を自動生成キーとして指定し、バッチの中で DEPT 表中の 2 行を更新し、更新された行の DEPTNO の値を取り出します。 選択されたステートメントの右にある番号は、前述のステップに対応しています。

import java.sql.*;
import com.ibm.db2.jcc.*;
…
Connection conn;
…
String[] agkNames = {"DEPTNO"};
try {
…
  conn.setAutoCommit(false);                             1 
  PreparedStatement ps = conn.prepareStatement(          2 
    "UPDATE DEPT SET  DEPTNAME=? " +
    "WHERE DEPTNO=?",agkNames);
  ps.setString(1,"X01");                                 3a 
  ps.setString(2,"Planning");
  ps.addBatch();                                         3b 
  ps.setString(1,"Y01");                          
  ps.setString(2,"Bookkeeping");
  ps.addBatch();                                  

  int [] numUpdates=ps.executeBatch();                   4 

  for (int i=0; i < numUpdates.length; i++) {            5a 
    if (numUpdates[i] == SUCCESS_NO_INFO)
      System.out.println("Execution " + i + 
        ": unknown number of rows updated");
    else
      System.out.println("Execution " + i + 
        "successful: " numUpdates[i] + " rows updated");
  }
  conn.commit();                                         5b 
  ResultSet[] resultList = 
    ((DB2PreparedStatement)ps).getDBGeneratedKeys();     5c 
  if (resultList.length != 0) {
    for (i = 0; i < resultList.length; i++) {
        while (resultList[i].next()) {
          String deptNoKey = rs.getString(1);
                              // Get automatically generated key
                              // value
          System.out.println("Automatically generated key value = " 
            + deptNoKey);
        }
    }
  }
  else {
    System.out.println("Error retrieving automatically generated keys");
  }
} 
catch(BatchUpdateException b) {                          6 
  // process BatchUpdateException
}