Realización de actualizaciones por lotes en aplicaciones JDBC

En las actualizaciones de proceso por lotes, en lugar de actualizar filas de una tabla de forma individual, puede hacer que JDBC ejecute un grupo de actualizaciones al mismo tiempo. Las sentencias que se pueden incluir en un mismo lote de actualizaciones se denominan sentencias procesables por lotes.

Acerca de esta tarea

Si una sentencia tiene parámetros de entrada o expresiones de lenguaje principal, puede incluir esa sentencia solo en un lote que tenga otras instancias de la misma sentencia. Este tipo de lote se denomina lote homogéneo. Si una sentencia carece de parámetros de entrada, puede incluir esa sentencia en un lote solo si las demás sentencias del lote no tienen parámetros de entrada ni expresiones de lenguaje principal. Este tipo de lote se denomina lote heterogéneo. Dos sentencias que se puedan incluir en el mismo lote se dice que son compatibles por lote.

Utilice los siguientes métodos de Statement para crear, ejecutar y eliminar un lote de actualizaciones SQL:
  • addBatch
  • executeBatch
  • clearBatch

Utilice el siguiente método de PreparedStatement y CallableStatement para crear un lote de parámetros para que una sentencia individual se pueda ejecutar varias veces en un lote, con un conjunto de parámetros diferente para cada ejecución.

  • addBatch
Restricciones en la ejecución de las sentencias de un lote:
  • Si intenta ejecutar una sentencia SELECT en un lote, se emite una excepción BatchUpdateException.
  • Un objeto CallableStatement que ejecute en un lote puede contener parámetros de salida. Sin embargo, no puede recuperar los valores de los parámetros de salida. Si intenta hacerlo, se emite una excepción BatchUpdateException.
  • No puede recuperar objetos ResultSet de un objeto CallableStatement que ejecute en un lote. En ese caso no se emite una excepción BatchUpdateException, pero la invocación del método getResultSet devuelve un valor nulo.

Procedimiento

Para realizar actualizaciones por lotes, siga uno de los grupos de pasos siguientes.

  • Para realizar actualizaciones por lotes utilizando varias sentencias sin parámetros de entrada, siga estos pasos básicos:
    1. Para cada sentencia de SQL que desee ejecutar en el lote, invoque el método addBatch.
    2. Invoque el método executeBatch para ejecutar el lote de sentencias.
    3. Compruebe si hay errores. Si no han ocurrido errores:
      1. Obtenga el número de filas afectadas por cada sentencia de SQL a partir de la matriz devuelta por la invocación de executeBatch. Este número no incluye las filas afectadas por activadores o por la aplicación de la integridad referencial.
      2. Si AutoCommit está inhabilitado para el objeto Connection, invoque el método commit para confirmar los cambios.

        Si se habilita AutoCommit para el objeto Connection , el IBM® Data Server Driver for JDBC and SQLJ añade un método commit al final del lote.

  • Para realizar actualizaciones por lotes utilizando una sola sentencia con varios conjuntos de parámetros de entrada, siga estos pasos básicos:
    1. Si la sentencia de proceso por lotes es un a sentencia UPDATE buscada, una sentencia DELETE buscada o sentencia MERGE buscada, establezca la modalidad de confirmación automática para la conexión en false.
    2. Invoque el método prepareStatement para crear un objeto PreparedStatement.
    3. Para cada conjunto de valores de parámetros de entrada:
      1. Ejecute métodos setXXX para asignar valores a los parámetros de entrada.
      2. Invoque el método addBatch para añadir el conjunto de parámetros de entrada al lote.
    4. Invoque el método executeBatch para ejecutar las sentencias con todos los conjuntos de parámetros.
    5. Si no han ocurrido errores:
      1. Obtenga el número de filas afectadas por cada ejecución de la sentencia de SQL a partir de la matriz devuelta por la invocación de executeBatch. El número de filas afectadas no incluye las filas afectadas por activadores o por la aplicación de la integridad referencial.

        Si se cumplen las siguientes condiciones, el IBM Data Server Driver for JDBC and SQLJ devoluciones Statement.SUCCESS_NO_INFO (-2), en lugar del número de filas que se vieron afectadas por cada instrucción SQL:

        • La aplicación está conectada a un subsistema que está en Db2 for z/OS® Versión 8 en modo de nuevas funciones, o posterior.
        • La aplicación utiliza la versión 3.1 o posterior de IBM Data Server Driver for JDBC and SQLJ.
        • El IBM Data Server Driver for JDBC and SQLJ utiliza operaciones INSERT de varias filas para ejecutar actualizaciones por lotes.

        Esto se debe a que, al realizar una operación INSERT de varias filas, el servidor de bases de datos ejecuta todo el proceso por lotes como una única operación, de forma que no devuelve resultados para sentencias de SQL individuales.

      2. Si AutoCommit está inhabilitado para el objeto Connection, invoque el método commit para confirmar los cambios.

        Si se habilita AutoCommit para el objeto Connection , el IBM Data Server Driver for JDBC and SQLJ añade un método commit al final del lote.

      3. Si el objeto PreparedStatement devuelve claves generadas automáticamente, invoque DB2PreparedStatement.getDBGeneratedKeys para recuperar una matriz de objetos ResultSet que contiene las claves generadas automáticamente.

        Compruebe la longitud de la matriz devuelta. Si la longitud de la matriz devuelta es 0, se ha producido un error durante la recuperación de las claves generadas automáticamente.

    6. Si se han producido errores, procese BatchUpdateException.

Ejemplo

En el siguiente fragmento de código de programa, se procesan por lotes dos conjuntos de parámetros. Luego, una sentencia UPDATE que admite dos parámetros de entrada se ejecuta dos veces, una vez con cada conjunto de parámetros. Los números que aparecen a la derecha de algunas sentencias corresponden a los pasos descritos anteriormente.

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
}

En el código de programa siguiente, una sentencia INSERT de proceso por lotes devuelve claves generadas automáticamente.

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
}

En el código de programa siguiente, una sentencia UPDATE de proceso por lotes devuelve claves generadas automáticamente. El código da nombre a la columna DEPTNO como una clave generada automáticamente, actualiza dos filas en la tabla DEPT de un proceso por lotes y recupera los valores de DEPTNO para las filas actualizadas. Los números que aparecen a la derecha de algunas sentencias corresponden a los pasos descritos anteriormente.

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
}