ResultSet con actualización


Introducción

En capítulos anteriores hemos podido obtener un conjunto de resultados a partir de una consulta. Además hemos visto como nos podemos desplazar por el conjunto de resultados. A continuación veremos como se pueden modificar los datos del conjunto y volcar las modificaciones en la base de datos.

Lo primero es comprobar si nuestro gestor de base de datos nos permite modificar conjuntos de resultados. Existen unas constantes static en la clase ResultSet que identifican el ResulSet en función de si pueden o no actualizar la base de datos:
CONCUR_READ_ONLY El ResultSet no puede modificar la base de datos.
CONCUR_UPDATABLE El ResultSet puede modificar la base de datos.

Una vez que hayamos establacido la conexión, tenemos que obtener un objeto de la clase Statement que admita actualizaciones de ResultSet. Para ello tenemos una versión de createStatement que dispará una excepción del tipo SQLException, en el caso de que la base de datos no permita el tipo señalado en resultSetType o resultSetConcurrency:

 public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException

Como ejemplo:

 String orden_SQL = "SELECT codigo, nombre FROM cliente ORDER BY nombre";
	  
  Statement sentencia = con.createStatement( ResultSet.TYPE_SCROLL_INSENSITIVE, 
ResultSet.CONCUR_UPDATABLE);
	    ResultSet rs = sentencia.executeQuery( orden_SQL 
);

Lo anterior es una forma sencilla y adecuada de tener un ResultSet actualizable. Veamos a continuación una forma erronea de crear un ResultSet actualizable. Si el objeto de tipo Statement se ha obtenido con la llamada a createStatement sin argumentos:

 Statement sentencia = con.createStatement( );
Nos puede ocurrir que al modificar el ResultSet:
 /*** Nos ponemos en el primero y lo modificamos ***/
	    rs.first();
	    rs.updateString( 
"nombre", "Joaquín");
	    rs.updateRow();
Se dispare una excepción. ¿Por qué? Estamos modificando un conjunto de resultados, pero el Statement del que proviene no admite esta capacidad:
 com.mysql.jdbc.NotUpdatable: Result Set not updatable.This result set must come 
from a statement that was created 
	with a result set type of ResultSet.CONCUR_UPDATABLE

También podemos saber si el conjunto permite actualización mediante un método de ResulSet:

 public int getConcurrency()

Que devuelve la capacidad del ResultSet en la forma de las constantes antes descritas. Otro método para averiguar la capacidad de un ResultSet implica el manejo de metadatos, que ya hemos visto en otros capítulos:

 boolean DatabaseMetaData.supportsResultSetConcurrency(int type, int concurrency) 
throws SQLException

Dispará una excepción del tipo SQLException, en el caso de que la base de datos no permita el tipo señalado en resultSetType o resultSetConcurrency.

Hay que tener en cuenta que no todas las consultas que nos devuelven un conjunto de resultados nos permiten actualización (aunque el gestor de base de datos si lo permita). La razón de esto puede ser que la consulta implique a varias tablas y que no estén enlazadas por el enlace de clave primaria - clave externa o que incluyendo varias tablas la consulta no incluya las claves primarias.

Actualizar

Unas sencillas líneas de ejemplo:

 /***** Definir sentencia y ejecutarla ********/
	    String orden_SQL = "SELECT 
codigo, nombre FROM cliente ORDER BY nombre";
	    Statement sentencia = con.createStatement( 
ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
	    ResultSet 
rs = sentencia.executeQuery( orden_SQL );

	    /*** Nos ponemos en el primero 
y lo modificamos ***/
	    rs.first();
	    rs.updateString( "nombre", "Joaquín");
	 
   rs.updateRow();

Lo primero es obtener un objeto Statement por medio de crateStatement; este objeto permite scroll (desplazamiento) y actualización . A continuación nos situamos mediante first() en la fila que queremos modificar (la primera) y realizamos el cambio de la columna "nombre" con updateString(), indicando en su segundo argumento el nuevo valor ("Joaquín"). Hay una versión de updateXXX() para cada tipo de campo: String, Double, etc.

Es importante destacar que la modificación se refiere al ResultSet, concretamente a la fila actual del ResultSet, y si nos movemos a otra fila los cambios se perderán, a menos que antes del desplazamiento llames a updateRow(). Unicamente updateRow() vuelca los cambios a la base de datos. Con el método cancelRowUpdates() cancelamos las modificaciones DE LA FILA ACTUAL.

Inserción y borrado

Después de haber aprendido la actualización, la inserción no resulta difícil. Lo primero es desplazar el cursor a una posición especial, una pseudofila en blanco, mediante una llamada a moveToInsertRow() de la clase ResultSet. A continuación usamos updateXXX( String nombre_columna, nuevo_valor ) para dar valores a las columnas:

 rs.moveToInsertRow();
	    rs.updateString( "codigo", "OJD33");
	    rs.updateString( 
"nombre", "Pedro Juan");
	    rs.updateInt( "edad", 34 );
	    rs.insertRow(); 
            // Guardar en base de datos
	    rs.moveToCurrentRow();      // Volvemos 
a la posición anterior a hacer moveToInsertRow

Con moveToCurrentRow() movemos el cursor a la posición anterior a la llamada a moveToInsertRow. En nuestro ejemplo la posición que ocupa el registro insertado depende de la cláusula ORDER BY de la consulta.

El borrado es extremadamente sencillo: el método deleteRow() borra la fila activa tanto del ResultSet como de la base de datos.

Sensatez

El manejo de ResultSet con actualización es una herramienta sencilla y muy utilizada. Pero conviene hacer alguna consideración:

  1. Resulta conveniente en aquellas aplicaciones en donde el usuario puede modificar de forma inmediata y extensa los registros. Por ejemplo, si presentas una tabla (JTable) y das al usuario la libertad para modificar cualquier fila. En cualquier otro caso es más eficiente usar las sentencias SQL INSERT, UPDATE o DELETE.

  2. Tener en cuenta las desventajas comparativas respecto a usar sentencias SQL con executeUpdate(): con un ResultSet hay que ejecutar una sentencia SELECT, localizar la fila adecuada y realizar la actualización. Esto puede ser menos eficiente que ejecutar directamente una sentencia SQL.

Volver al índice