problema de java con DB2 UDB sobre unix AIX

francisco
27 de Diciembre del 2002
Descripción del problema.

Al ejecutar una sentencia de tipo “SELECT” por medio de un objeto ResultSet desde una aplicación Java se obtiene el error de DB2 UDB “SQL0973N”: APP_CTL_HEAP excedido. La composición de lugar es la siguiente:

- Definición de la tabla del problema:

CREATE TABLE myTable (col1 varchar(1024), col2 blob(32000))

- Sentencia SQL que se ejecuta:

SELECT * FROM myTable

- Código Java que la ejecuta:

import java.sql.*;
...
String url = "jdbc:db2:dbalf";
String query = "SELECT * FROM myTable";
Statement stmt;
long lng = 0;

try
{
//Carga el driver.
Class.forName ("COM.ibm.db2.jdbc.app.DB2Driver");

//Establece propiedades de conexión.
Properties p;
p = new Properties();
p.setProperty("UID", "Administrator");
p.setProperty("PWD", "localadmin");

//Abre la connexion y establece valores..
Connection con = DriverManager.getConnection (url, p);
con.setReadOnly(true);
con.setAutoCommit(false);

//Crea statement para ResultSet.
stmt = con.createStatement (ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
stmt.setCursorName("PRDB2");

//Abre ResultSet.
ResultSet rs = stmt.executeQuery (query);

//Mientras hay datos los imprime.
while (rs.next())
{
System.out.println(rs.getString(1));
}
rs.close();
stmt.close();
con.close();
}
…
Leyendo la documentación de IBM observamos que el parámetro APP_CTL_HEAP se puede incrementar subiendo APP_CTL_HEAP_SZ, el problema es que la tabla tiene más de un millón y medio de registros y cada día entran más, es decir, que nunca se puede aumentar lo suficiente como para que no falle (no tenemos memoria ilimitada en el servidor). Por lo tanto, esta solución no es posible llevarla a cabo, no podemos subir el parámetro APP_CTL_HEAP_SZ tanto como para asegurar que la aplicación Java no falle.

Por otro lado, también hemos visto que el APP_CTL_HEAP se libera cuando se ejecuta un COMMIT. Intentamos hacerlo, pero al ejecutar COMMIT modificando el programa del modo:

…
while (rs.next())
{
lng++;
System.out.println(rs.getString(1));
if (lng%500 == 0)
{
System.out.println("n" + lng);
stmt.executeUpdate("COMMIT");
}
}
…

comprobamos que se pierde el cursor. Así que intentamos abrirlo del modo WITH HOLD de varios modos:

- Cambiando la sentencia SELECT:

SELECT * FROM myTable WITH UR FOR FETCH ONLY

- Cambiando las propiedades de conexión, añadiendo:

p.setProperty("CURSORHOLD", "1");

y ninguna de las dos opciones ha resultado, al hacer COMMIT se pierde el cursor en todos los casos (también hemos probado en la SELECT con WITH UR, WITH RR, WITH CS y WITH RS, pero ninguna da los resultados esperados). Incluso intentamos crear el objeto Statement de ejecución de la sentencia del modo:

Statement stmt = con.createStatement (ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);

disponible a partir de la version 1.4 de Java, pero parece que el driver JDBC de DB2 UDB no implementa el método createStatement con el tercer parámetro (ResultSet.HOLD_CURSORS_OVER_COMMIT).

El caso es que en esta situación parece que no podemos hacer la SELECT que necesitamos. Hemos comprobado que en un programa Visual Basic con el driver OLE DB y ADO si que funciona si ponemos en los parámetros de conexión CURSORHOLD=1, pero desde Java no hemos podido hacerlo funcionar.

Buscamos dos posibles alternativas:

1. Deshabilitar el heap APP_CTL_HEAP para que no almacene nada ahí y no haya fallos de este tipo.
2. Poder poner CURSORHOLD en la aplicación Java para que guarde el cursor después del COMMIT.


También hemos comprobado que si aumentamos el tamaño del parámetro APP_CTL_HEAP_SZ obtenemos otro error: MAXIMUM NUMBER OF LOB LOCATORS EXCEDED. Según hemos visto, DB2 UDB tiene una limitación con respecto a los campos de tipo LOB, que no se pueden recuperar más de 32100 registros que contengan un campo de este tipo con una sola sentencia; aunque pensamos que este problema se eliminará también si conseguimos no tener el APP_CTL_HEAP activado o si conseguimos hacer COMMIT regularmente sin problemas desde Java.