introjdbc

27
Introducción a JDBC 1. Introducción. JDBC significa Java Data Base Connectivity. Comprende las clases utilizadas para conectar con bases de datos. Hace uso intensivo del mecanismo de excepciones, que se basa en abortar la ejecución de métodos cuando alguna instrucción falla. Las clases que describen las fallas se conoce como excepciones. 1.1. Biblioteca de Clases JDBC. El primer elemento que se necesita es la librería que contiene las clases necesarias para conectar un programa con un manejador de bases de datos específico. En el caso de Derby hay dos formas de operación: Embedded. En español se conoce como empotrado. La base de datos es manejada directamente por el programa. No necesita activar un servidor. Solamente puede ser utilizada por un programa a la vez. Client. En español se conoce como cliente. El programa se conecta a un servidor de bases de datos, que da servicio a varios programas a la vez. A continuación se listan los nombres de las librerías para algunas bases de datos y la forma de conseguirlos. Base de Datos Archivo Forma de conseguirlo Derby (Embedded) “derby.jar” Incluido en el JDK 1.6.0, en la carpeta “C:\Archivos  de Programa\Java\jdk1.6.0\db\lib”.  Para versiones posteriores se encuentra en “C:\Archivos de Programa\Sun\JavaDB\lib” Derby (Client) “derbyclient.jar” Incluido en el JDK 1.6.0, en la carpeta “C:\Archivos  de Programa\Java\jdk1.6.0\db\lib”.  Para versiones posteriores se encuentra en “C:\Archivos de Programa\Sun\JavaDB\lib” MySQL “mysql-connector-java-XXX-bin.jar”, donde XXX es la versión. Por ejemplo, para la versión 5.1.6 el archivo es: “mysql-connector-java-5.1.6-bin.jar” Descarga del sitio: http://mysql.com 1 / 27

Transcript of introjdbc

Page 1: introjdbc

Introducción a JDBC

1. Introducción.JDBC significa Java Data Base Connectivity. Comprende las clases utilizadas para conectar con bases de datos. Hace uso intensivo del mecanismo de excepciones, que se basa en abortar la ejecución de métodos   cuando   alguna   instrucción   falla.   Las   clases   que   describen   las   fallas   se   conoce   como excepciones.

1.1. Biblioteca de Clases JDBC.El primer elemento que se necesita es la librería que contiene las clases necesarias para conectar un programa con un manejador de bases de datos específico.

En el caso de Derby hay dos formas de operación:

● Embedded. En español se conoce como empotrado. La base de datos es manejada directamente por   el   programa.   No   necesita   activar   un   servidor.   Solamente   puede   ser   utilizada   por   un programa a la vez.

● Client. En español se conoce como cliente. El programa se conecta a un servidor de bases de datos, que da servicio a varios programas a la vez.

A  continuación   se   listan   los  nombres  de   las   librerías  para   algunas  bases  de  datos  y   la   forma  de conseguirlos.

Base de Datos Archivo Forma de conseguirlo

Derby (Embedded)

“derby.jar” Incluido   en   el   JDK   1.6.0,   en   la   carpeta “C:\Archivos   de Programa\Java\jdk1.6.0\db\lib”.   Para versiones   posteriores   se   encuentra   en “C:\Archivos de Programa\Sun\JavaDB\lib”

Derby (Client) “derbyclient.jar” Incluido   en   el   JDK   1.6.0,   en   la   carpeta “C:\Archivos   de Programa\Java\jdk1.6.0\db\lib”.   Para versiones   posteriores   se   encuentra   en “C:\Archivos de Programa\Sun\JavaDB\lib”

MySQL “mysql­connector­java­XXX­bin.jar”, donde XXX es la versión. Por ejemplo, para   la   versión   5.1.6   el   archivo   es: “mysql­connector­java­5.1.6­bin.jar”

Descarga del sitio:http://mysql.com

1 / 27

Page 2: introjdbc

Introducción a JDBC

Base de Datos Archivo Forma de conseguirlo

Oracle “ojdbc14,jar” Descarga del sitio:http://oracle.com

Estos archivos se deben incluir CLASSPATH. Por ejemplo, en Windows puede tenerse la siguiente instrucción desde el símbolo del sistema o algún archivo bat:

set CLASSPATH=.;C:\Archivos de Programa\Java\jdk1.6.0\db\lib\derby.jar

o bien, al ejecutar algún archivo, por ejemplo la clase JDBC, se puede usar la siguiente instrucción:

java ­cp “.;C:\Archivos de Programa\Java\jdk1.6.0\db\lib\derby.jar” JDBC

En caso de trabajar en algún ambiente de programación, normalmente se define un proyecto y en sus propiedades se puede definir la variable CLASSPATH.

1.2. Carga del Controlador de Conexiones.Para realizar la conexión a una base de datos desde el programa, el primer paso es cargar la clase del controlador de conexiones específico de la base de datos. A continuación se lista el nombre de esta clase para distintas bases de datos.

Base de Datos Clase

Derby (Embedded) org.apache.derby.jdbc.EmbeddedDriver

Derby (Client) org.apache.derby.jdbc.ClientDriver

MySQL com.mysql.jdbc.Driver

Oracle oracle.jdbc.OracleDriver

La carga del controlador de conexiones es realizada por la clase Class, que se encarga de administrar las clases de Java. En particular, cuenta con un método que se llama forName, que busca una clase de acuerdo   a   las   indicaciones   del   CLASSPATH   y   cargarla;   si   no   la   encuentra,   lanza   la   excepción java.lang.ClassNotFoundException. A continuación se ejemplifica como cargar el controlador para Derby embedded.

Class.forName("org.apache.derby.jdbc.EmbeddedDriver");

2 / 27

Page 3: introjdbc

Introducción a JDBC

Esta instrucción solo se ejecuta una vez en el programa y debe invocarse antes de las instrucciones de acceso a bases de datos; de lo contrario se genera una excepción de tipo java.sql.SQLException con el mensaje "No suitable driver".

1.3. Conexión a la Base de Datos.El siguiente paso es establecer la conexión a la base de datos. La encargada es la clase DriverManager, con el método getConnection. Recibe tres parámetros:

● URL. Significa "Universal Resource Locator" (Localizador Universal de Recursos) y es una cadena que sirve para ubicar un recurso en una red. Consta de 4 partes: 

○ Protocolo. Es el lenguaje de comunicación. Por ejemplo, http, https, tcp, etc. Para comunicarse desde Java a bases de datos, el protocolo es jdbc.

○ Host.  Es  la computadora donde está  alojada  la base de datos.  Puede ser el  nombre del servidor  o   su  dirección   IP.  Cuando  el   servidor   corre   en   la  misma computadora  que  el programa, el nombre del servidor puede ser “127.0.0.1” o también “localhost”. En algunas ocasiones incluye también el número de puerto, que es un número asignado de forma única a un programa. Por ejemplo, el servidor de Oracle generalmente utiliza el puerto 1521. 

○ Recurso. Nombre del recurso a utilizar. Puede tratarse de un archivo, de una impresora o una base de datos. En el caso de Oracle se utiliza el ORASID y en otros manejadores es el nombre de la base de datos.

○ Opciones. Especifican formas de manejar la conexión o la base de datos. Por ejemplo, en Derby embedded la opción "create=true" permite crear la base de datos en caso de que no exista.

● Usuario. Nombre de usuario para realizar la conexión. Es validado por la base de datos.

● Password. Contraseña correspondiente a la base de datos. Es validado por la base de datos.

A continuación se muestra como construir el URL para distintos manejadores.

● Derby (Embedded)

Formato:“jdbc:derby:recurso;opciones”

Ejemplos:“jdbc:derby:proveedores;create=true”

“jdbc:derby:pedidos”

3 / 27

Page 4: introjdbc

Introducción a JDBC

● Derby (Client)

Formato:“jdbc:derby://host:puerto/recurso;opciones”

Ejemplos:“jdbc:derby://localhost:1527/proveedores;create=true”

“jdbc:derby:pedidos”

● MySQLFormato:

"jdbc:mysql://host:puerto/recurso"

Ejemplos:"jdbc:mysql://localhost/test"

"jdbc:mysql://localhost:3306/test"

● OracleFormato:

"jdbc:oracle:thin:@host:puerto:orasid"

Ejemplo:"jdbc:oracle:thin:@192.168.7.221:1521:oracledb"

El resultado de la operación  getConnection  es una instancia de la interfaz  java.sql.Connection, que representa la conexión a la base de datos. Si no se puede realizar porque no se ha cargado el controlador de conexión. la combinación usuario/password es incorrecta, no hay red o algún otro error, se lanza una excepción del tipo java.sql.SQLException. A continuación se muestra un ejemplo de como establecer la conexión.

Connection c = DriverManager.getConnection("jdbc:derby:proveedores;create=true",                                   "juan", "chimo1267");

En este ejemplo, el url es  "jdbc:derby:proveedores;create=true";  el usuario es  “"juan" y el password es "chimo1267".

En el caso de que no se haya cargado el manejador de conexiones o el URL sea incorrecto, el mensaje de la excepción es “No suitable driver”.

Al final de la sesión siempre hay que cerrar la conexión. En algunas bases de datos y  configuraciones es forzoso cerrar la conexión. Se utiliza la instrucción close, que genera también una excepción del tipo java.sql.Exception cuando algo sale mal.

4 / 27

Page 5: introjdbc

Introducción a JDBC

Ejemplo:1234567891011121314151617181920212223242526272829303132333435363738394041424344

import java.sql.Connection;import java.sql.DriverManager;import java.sql.SQLException;

public class Conexion { /** Método Principal. Puede abortar su ejecución por alguna de las * excepciones indicadas después de throws. * @param args Parámetros de la aplicación. * @throws java.lang.ClassNotFoundException Si no encuentra la clase * que controla el acceso a la base de datos. * @throws java.sql.SQLException Si ocurre un error durante la sesión * con la base de datos. */ public static void main(String[] args) throws ClassNotFoundException, SQLException { /* Carga en la memoria la clase que controla la conexión a la base de * datos. */ Class.forName("org.apache.derby.jdbc.EmbeddedDriver"); /* URI que permite establecer una sesión con la base de datos. El * nombre de la base de datos es "ejemplo". La opción create=true * indica que la base de datos se debe crear en caso de que no * exista. */ final String url = "jdbc:derby:ejemplo;create=true"; // Usuario para establecer sesión con la base de datos. final String usuario =""; // Contraseña para establecer sesión con la base de datos. final String contraseña = ""; Connection c = null; try { /* Establece una sesión con la base de datos. Se administra con * un objeto de la clase "Connectión". Si no puede establecerse, * lanza una excepción y la referencia "c" sigue valiendo null.*/ c = DriverManager.getConnection(url, usuario, contraseña); } finally { /* Esta sección se ejecuta siempre; cuando se lanza una excepción * o cuando todo se ejecuta sin problemas. Cuando c != null, es * porque la conexión se estableció y por lo mismo, hay que * cerrarla. Si c == null, no fué posible establecer la conexión * y por lo mismo no hay que hacer nada. */ if (c != null) { c.close(); } } }}

1.4. Envío de Instrucciones SQL al Manejador.Hay varias formas para ejecutar una instrucción en SQL. Una de ellas es con una instancia de la interfaz java.sql.Statement  y se usa cuando la consulta se conoce totalmente al momento de escribir  el 

5 / 27

Page 6: introjdbc

Introducción a JDBC

programa. El siguiente ejemplo muestra como crear un objeto de este tipo.

Statement s = c.createStatement();

Para enviar la manejador una instrucción que modifique datos, solo hay que enviarla como parámetro del  método  executeUpdate  de   la   clase  java.sql.Satatement.  Devuelve   el   número  de   registros modificados. En caso de que la instrucción no se pueda ejecutar porque su formato sea incorrecto o alguna otra razón se genera una excepción del tipo java.sql.SQLException. He aquí un ejemplo:

s.executeUpdate("CREATE TABLE Puesto (" + "clave INTEGER PRIMARY KEY, " + "nombre VARCHAR(20) NOT NULL, " + "sueldoMensual NUMERIC(8,2) NOT NULL, " + "horaDeEntrada TIME NOT NULL, " + "horaDeSalida TIME NOT NULL, " + "fechaDeCreacion DATE NOT NULL)");

Esta instrucción crea la tabla puesto.

Cuando una instancia de Statement ya no se usa también debe cerrarse. Tiene un método close que lanza una SQLException cuando algo sale mal. 

Ejemplo:123456789

101112131415161718192021

import java.sql.Connection;import java.sql.DriverManager;import java.sql.SQLException;import java.sql.Statement;

public class CreaBD { public static void main(String[] args) throws ClassNotFoundException { Class.forName("org.apache.derby.jdbc.EmbeddedDriver"); Connection c = null; Statement s = null; try { c = DriverManager.getConnection("jdbc:derby:eventos;create=true", "", ""); s = c.createStatement(); s.executeUpdate("CREATE TABLE Puesto (" + "clave INTEGER PRIMARY KEY, " + "nombre VARCHAR(20) NOT NULL, " + "sueldoMensual NUMERIC(8,2) NOT NULL, " + "horaDeEntrada TIME NOT NULL, " + "horaDeSalida TIME NOT NULL, " + "fechaDeCreacion DATE NOT NULL)");

6 / 27

Page 7: introjdbc

Introducción a JDBC

222324252627282930313233343536373839404142434445464748

s.executeUpdate("CREATE TABLE Evento (" + "clave INTEGER PRIMARY KEY " + " GENERATED ALWAYS AS IDENTITY, " + "nombre VARCHAR(30) NOT NULL, " + "fechaYHora TIMESTAMP NOT NULL)"); s.executeUpdate("CREATE TABLE Sala (" + "nombre VARCHAR(16) PRIMARY KEY, " + "descripcion VARCHAR(30) NOT NULL)"); System.out.println("Base de datos creada."); } catch (SQLException e) { System.out.println("Error de JDBC: " + e.getMessage()); System.out.println("Error de JDBC: " + e.getLocalizedMessage()); e.printStackTrace(); } finally { if (s != null) { try { s.close(); } catch (SQLException e) {} } if (c != null) { try { c.close(); } catch (SQLException e) {} } } }}

1.5. Inserción de Datos y Secuencias de Escape.En algunos aspectos los manejadores de base de datos tienen una sintaxis totalmente diferente. Es por ello que JDBC introduce secuencias de escape que los controladores convierten en la sintaxis correcta para el manejador utilizado al instante de ejecutarse. Siempre se ponen entre llaves ({}). Tienen el siguiente formato: {palabra_clave parámetros}. Por ejemplo, en {d '2003-10-3'}, la palabra_clave es d y el parámetro es '2003-10-3'. A continuación se listan las secuencias de escape.

● escape.   Caracteres   de   escape   para   el   operador   LIKE.  Normalmente   el   caracter   '%' corresponde a cero o más caracteres y el caracter '_' representa un caracter. Si se quiere eliminar este comportamiento e interpretar el caracter literalmente, debe ser precedido por una diagonal invertida ('\'), que se conoce como caracter de escape. Se puede especificar otro caracter de escape con la siguiente secuencia al final de la consulta:

{escape 'caracter_de_escape'}

En el siguiente ejemplo, se define una diagonal invertida como caracter de escape y selecciona a todos los proveedores cuyo correo electrónico lleve guión bajo.

s.executeQuery("SELECT * FROM Conocido WHERE con_email LIKE '%\_%'"

7 / 27

Page 8: introjdbc

Introducción a JDBC

+ "{escape '\'}");

● fn.   Funciones   escalares.  Casi   todos   los   manejadores   de   base   de   datos   tienen   definidas funciones que devuelven valores de distintos tipos. Pueden invocarse con la palabra clave fn, seguida de la invocación a la función deseada, incluyendo sus argumentos. El siguiente ejemplo concatena dos textos.

{fn concat('texto1', 'texto2')}

Las funciones soportadas varían según el manejador. (Nada es perfecto.)

● d. Literales tipo fecha. La fecha se especifica con la siguiente sintaxis:

{d 'año-mes-día'}

Donde año se indica con un número de cuatro dígitos, mes se indica con un número del 1 al 12 y día es el día del mes, de 1 a 31.

● t. Literales tipo hora. Las horas se especifican con el siguiente formato.

{t 'hora:minutos:segundos'}

 hora es de 0 a 23. minutos y segundos son de 0 a 59.

● ts. Literales para fecha y hora juntas (timestamp). Se utiliza el siguiente formato; la forma de especificar año, mes y día es la misma que para especificar solamente fechas.

{ts 'año-mes-día hora:minutos:segundos.fracciones_de_segundo'}

.fracciones_de_segundo se puede omitir.

● oj. Outer joins. La sintaxis es la siguiente.

{oj outer_join}

La sintaxis para outer_join es:

tabla tipo_de_join OUTER JOIN tabla_o_outer_join ON condición

El tipo_de_join puede ser LEFT, RIGHT o FULL. tabla_o_outer_join puede ser el nombre de una tabla o bien otro outer_join. El siguiente ejemplo utiliza esta secuencia de escape.

s.executeQuery("SELECT * FROM { oj Producto LEFT OUTER JOIN " + "TipoDeProducto ON prod_clave = 1}");

8 / 27

Page 9: introjdbc

Introducción a JDBC

Una vez más,  el   tipo  de   join  que  se puede usar,  depende del  manejador  de  base de  datos empleado.

El  uso de secuencias  de escape está  habilitado de forma predeterminada,  pero puede habilitarse o deshabilitarse con el método de objeto  Statement.setEscapeProcessing.

Ejemplo:123456789

101112131415161718192021222324252627282930313233343536373839404142

import java.sql.Connection;import java.sql.DriverManager;import java.sql.SQLException;import java.sql.Statement;

public class Insercion { public static void main(String[] args) throws ClassNotFoundException, SQLException { Class.forName("org.apache.derby.jdbc.EmbeddedDriver"); Connection c = null; Statement s = null; try { // En estre caso no crea la base de datos. c = DriverManager.getConnection("jdbc:derby:eventos", "", ""); s = c.createStatement(); int agregados = s.executeUpdate("INSERT INTO Sala " + "(nombre, descripcion) " + "VALUES ('Imperial', 'Para eventos importantes.'), " + "('Cool', 'Para eventos de jóvenes.')"); System.out.println("Salas agregadas: " + agregados + "."); agregados = s.executeUpdate("INSERT INTO Puesto " + "(clave, nombre, sueldoMensual, horaDeEntrada, " + "horaDeSalida, fechaDeCreacion) " + "VALUES (1, 'Capturista', 3200.50, {t '09:00:00'}, " + "{t '18:00:00'}, {d '2005-02-01'})"); System.out.println("Puestos agregados: " + agregados + "."); /* En este caso no se proporciona valor para la clave porque se * genera automáticamente */ s.executeUpdate("INSERT INTO Evento (nombre, fechaYHora) " + "VALUES ('Boda', {ts '2009-03-10 20:00:00'})"); System.out.println("Evento agregado."); } finally { if (s != null) { try { s.close(); } catch (SQLException e) {} } if (c != null) { c.close(); } } }

9 / 27

Page 10: introjdbc

Introducción a JDBC

43 }

1.6. Modificación de Datos.

123456789

1011121314151617181920212223242526272829303132333435363738

import java.sql.Connection;import java.sql.DriverManager;import java.sql.SQLException;import java.sql.Statement;

public class Modificacion { public static void main(String[] args) throws ClassNotFoundException, SQLException { Class.forName("org.apache.derby.jdbc.EmbeddedDriver"); Connection c = null; Statement s = null; try { c = DriverManager.getConnection("jdbc:derby:eventos", "", ""); s = c.createStatement(); int modificados = s.executeUpdate("UPDATE Puesto " + "SET horaDeSalida = {t '15:00:00'}, " + "sueldoMensual = sueldoMensual + 1000 " + "WHERE clave < 3"); System.out.println("Registros modificados: " + modificados); modificados = s.executeUpdate("UPDATE Puesto " + "SET horaDeEntrada = {t '9:00:00'}"); System.out.println("Registros modificados: " + modificados); modificados = s.executeUpdate("UPDATE Sala SET " + "descripcion = 'Para los mejores eventos.' " + "WHERE nombre = 'Imperial'"); System.out.println("Registros modificados: " + modificados); } finally { if (s != null) { try { s.close(); } catch (SQLException e) {} } if (c != null) { c.close(); } } }}

1.7. Eliminación de Datos.

123

import java.sql.Connection;import java.sql.DriverManager;import java.sql.SQLException;

10 / 27

Page 11: introjdbc

Introducción a JDBC

456789

101112131415161718192021222324252627282930313233

import java.sql.Statement;

public class Eliminacion { public static void main(String[] args) throws ClassNotFoundException, SQLException { Class.forName("org.apache.derby.jdbc.EmbeddedDriver"); Connection c = null; Statement s = null; try { c = DriverManager.getConnection("jdbc:derby:eventos", "", ""); s = c.createStatement(); int eliminados = s.executeUpdate("DELETE FROM Sala " + "WHERE nombre = 'Imperial'"); System.out.println("Eliminados de Sala: " + eliminados); eliminados = s.executeUpdate("DELETE FROM Evento " + "WHERE clave = 1"); System.out.println("Eliminados de Evento: " + eliminados); } finally { if (s != null) { try { s.close(); } catch (SQLException e) {} } if (c != null) { c.close(); } } }}

1.8. Consulta de Datos.El método executeQuery permite recuperar datos con el uso de una instrucción SELECT de SQL. El valor devuelto es una instancia de la clase  java.sql.ResultSet,  que representa una colección de registros. Este es un ejemplo de como recuperar datos.

ResultSet rs = s.executeQuery("SELECT * FROM Conocido");

La clase java.sql.ResultSet tiene los siguientes métodos:

● next(). Permite avanzar al siguiente registro. Cuando es posible avanzar, devuelve true. Si no existe un siguiente registro, devuelve false.

● previous(). Permite regresar al registro que le precede al actual. Cuando es posible avanzar, devuelve  true.  Si  no  existe  un   registro  anterior,  devuelve  false.  Requiere  que  al  crear   la instancia de Statement se defina del tipo ResultSet.TYPE_SCROLL_INSENSITIVE.

11 / 27

Page 12: introjdbc

Introducción a JDBC

● beforeFirst().   Se   coloca   antes   del   primer   registro.   Es   la   posición   donde   se   posiciona originalmente. Si posteriormente a este método se invoca next(), se recupera el primer registro. Requiere   que   al   crear   la   instancia   de  Statement se   defina   del   tipo ResultSet.TYPE_SCROLL_INSENSITIVE.

● afterLast(). Se coloca después del último registro. Si posteriormente a este método se invoca previous(), se recupera el último registro. Requiere que al crear la instancia de Statement se defina del tipo ResultSet.TYPE_SCROLL_INSENSITIVE.

● last(). Se coloca en el último registro. Requiere que al crear la instancia de  Statement se defina del tipo ResultSet.TYPE_SCROLL_INSENSITIVE.

● first(). Se coloca en el primer registro. Requiere que al crear la instancia de Statement se defina del tipo ResultSet.TYPE_SCROLL_INSENSITIVE.

● getRow(). Devuelve el número del registro actual. El primer registro devuelve 1. invocar este método después de last() proporciona el número total de registros devuelto.

● getInt(“campo”), getString(“campo”). Obtiene el valor del campo indicado para el registro actual y lo convierte al tipo indicado después del prefijo get. Por ejemplo, 

int a = rs,getInt("con_clave");

devuelve el valor de  con_clave  y lo interpreta como entero. Si el valor no se puede convertir al tipo indicado, se genera uan SQLException.

● getDate(“campo”). Devuelve una referencia a un objeto de tipo java.sql.Date, que solo pone valor a día, mes y año; las horas, minutos y segundos se ponen en cero, a diferencia del tipo java.util.Date,   del   cual   se   deriva,   que   también   asigna   estos   valores.   Hay   otras   clases derivadas de java.sql.Date que se usan: java.sql.Time para manejar solo el tiempo (horas, minutos y segundos) y  java.sql.Timestamp  que maneja fecha y hora,  con una resolución hasta nanosegundos.

● close(). Libera los recursos utilizados cuando se deja de usar el objeto.

Ejemplo 1:123456789

10111213

import java.sql.Connection;import java.sql.DriverManager;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;

public class ConsultaSalas { public static void main(String[] args) throws ClassNotFoundException, SQLException { Class.forName("org.apache.derby.jdbc.EmbeddedDriver"); Connection c = null; Statement s = null; ResultSet rs = null;

12 / 27

Page 13: introjdbc

Introducción a JDBC

1415161718192021222324252627282930313233343536373839

try { c = DriverManager.getConnection("jdbc:derby:eventos", "", ""); s = c.createStatement(); rs = s.executeQuery("SELECT * FROM Sala"); while (rs.next()) { System.out.println(rs.getString("nombre") + "|" + rs.getString("descripcion")); } rs.close(); } finally { if (rs != null) { try { rs.close(); } catch (SQLException e) {} } if (s != null) { try { s.close(); } catch (SQLException e) {} } if (c != null) { c.close(); } } }}

Ejemplo 2:123456789

1011121314151617181920212223

import java.sql.Connection;import java.sql.DriverManager;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;

public class Consultas { public static void main(String[] args) throws ClassNotFoundException, SQLException { Class.forName("org.apache.derby.jdbc.EmbeddedDriver"); Connection c = null; Statement s = null; ResultSet rs = null; try { c = DriverManager.getConnection("jdbc:derby:eventos", "", ""); s = c.createStatement(); rs = s.executeQuery("SELECT * FROM Puesto"); System.out.println("PUESTOS:"); while (rs.next()) { System.out.printf("|%1$6d|%2$-15s|%3$,11.2f|" + "%4$tH:%4$tM |%5$td/%5$tm/%5$tY|%n", rs.getInt("clave"), rs.getString("nombre"), rs.getDouble("sueldoMensual"),

13 / 27

Page 14: introjdbc

Introducción a JDBC

24252627282930313233343536373839404142434445464748495051525354

rs.getTime("horaDeEntrada"), rs.getDate("fechaDeCreacion")); } rs.close(); rs = s.executeQuery("SELECT * FROM Evento"); System.out.println("EVENTOS:"); while (rs.next()) { System.out.printf("|%1$5d|%2$-10s|%3$td/%3$tm/%3$tY |" + "%3$tH:%3$tM |%n", rs.getInt("clave"), rs.getString("nombre"), rs.getTimestamp("fechaYHora")); } } finally { if (rs != null && !rs.isClosed()) { try { rs.close(); } catch (SQLException e) { } } if (s != null) { try { s.close(); } catch (SQLException e) { } } if (c != null) { c.close(); } } }}

1.9. Consultas con Parámetros.En algunas ocasiones la información a enviar a la base de datos no se conoce al momento de escribir el programa, o bien se quiere repetir varias veces la misma instrucción, pero con diferentes datos. En este caso   es   conveniente   utilizar   la   clase  java.sql.PreparedStatement,   que   se   deriva   de   la   clase java.sql.Statement.

Al momento de crear la consulta, se usan signos de interrogación ('?') para definir parámetros. He aquí un ejemplo de como crearla. La variable c es una instancia de java.sql.Connection.

PreparedStatement ps = c.prepareStatement("INSERT INTO Conocido " + "(con_clave, con_nombre, con_telefono, " + " con_email, con_fecha, con_direccion) " + "VALUES(?, ?, ?, ?, ?, ?)");

                                    parámetro 1   parámetro 2    parámetro 3    parámetro 4

14 / 27

Page 15: introjdbc

Introducción a JDBC

Loa parámetros se buscan desde el inicio de la consulta y solo se toma en cuenta el orden.

Cuando se desea realizar una consulta cuyos registros de revisan hacia adelante y hacia atrás, se puede usar una instrucción como la que sigue:

PreparedStatement ps = c.prepareStatement("SELECT * FROM Conocido " + "WHERE con_fecha < ?", ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);

En este ejemplo, se crean seis parámetros al final de la consulta y están indicados por los signos de interrogación. Se identifican por su orden de aparición. Así el parámetro 1 corresponde al primer signo de interrogación, el parámetro 2 al segundo signo de interrogación y así sucesivamente.

En este momento, algunos manejadores de bases de datos compilan y optimizan la consulta, de tal forma  que  es  más   rápido  crear   la   consulta  y  utilizarla  varia  veces,  que  usar  varias   consultas  por separado.

Antes de ejecutar la instrucción se asigna valor a todos los parámetros. Dicho valor se coloca con la sintaxis adecuada en lugar del signos de interrogación. A continuación se muestra como asignar valor. La variable fmt apunta a una instancia de java.util.DateFormat y se encarga de crear un objeto de java.util.Date a partir de un texto.

ps.setInt(1, 3); // valor del signo de interrogación 1 ps.setString(2, "Armando Pacheco"); // signo 2 ps.setString(3, "01-800-TQUILA"); // signo 3 ps.setString(4, "[email protected]"); ps.setString(5, "Noche de Ronda #99"); ps.setDate(6, new Date(fmt.parse("23/2/2007").getTime()));

En el caso de las fechas (parámetro 6), debe asignarse una instancia de  java.sql.Date, cuyo único constructor recibe un long que representa la fecha. Este valor puede obtenerse con el método getTime de java.util.Date. Para obtener la fecha deseada puede utilizarse

java.util.Date fecha = fmt.parse("23/2/2007");

Una vez obtenida la fecha, el número de tipo long que la representa, se obtienen así

long número = fecha.getTime();

Con este número, la instancia de java.sql.Date se obtiene de esta forma:

java.sql.Date fechaSQL = new java.sql.Date(número);

15 / 27

Page 16: introjdbc

Introducción a JDBC

Cuando todos los parámetros están asignados, puede invocarse executeUpdate o executeQuery según el tipo de instrucción SQL.

int modificados = ps.executeUpdate();ResultSet rs = ps.executeQuery();

Una vez invocada, se puede cambiar el valor de los parámetros y ejecutarse una vez más. Este proceso puede repetirse las veces deseadas.

ps.setInt(1, 4); // Cambia los valores anteriores ps.setString(2, "Pancracio Wellington"); ps.setString(3, "01-800-PLATANOS"); // signo 3 ps.setString(4, "[email protected]"); ps.setString(5, "Paseo de los plátanos #99"); ps.setDate(6, new Date(fmt.parse("23/2/2007").getTime()));

ps.executeUpdate();

Para esta clase, no se permite deshabilitar las secuencias de escape.

Ejemplo:123456789

1011121314151617181920212223242526272829

import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;import java.sql.Time;import java.sql.Timestamp;import java.text.ParseException;import java.text.SimpleDateFormat;

public class InsercionParametros { public static void main(String[] args) throws ClassNotFoundException, SQLException, ParseException { Class.forName("org.apache.derby.jdbc.EmbeddedDriver"); final SimpleDateFormat df = new SimpleDateFormat("dd/MM/yyyy"); final SimpleDateFormat tf = new SimpleDateFormat("HH:mm"); final SimpleDateFormat tsf = new SimpleDateFormat("dd/MM/yyyy HH:mm"); Connection c = null; PreparedStatement ps = null; ResultSet rs = null; try { c = DriverManager.getConnection("jdbc:derby:eventos", "", ""); ps = c.prepareStatement("INSERT INTO Puesto " + "(clave, nombre, sueldoMensual, horaDeEntrada, " + "horaDeSalida, fechaDeCreacion) " + "VALUES (?, ?, ?, ?, ?, ?)"); ps.setInt(1, 2);

16 / 27

Page 17: introjdbc

Introducción a JDBC

30313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475

ps.setString(2, "Analista"); ps.setDouble(3, 20000.45); ps.setTime(4, new Time(tf.parse("10:30").getTime())); ps.setTime(5, new Time(tf.parse("16:00").getTime())); ps.setDate(6, new java.sql.Date(df.parse("3/11/2000").getTime())); ps.executeUpdate(); // Los parámetros pueden asignarse en desorden. ps.setTime(5, new Time(tf.parse("9:00").getTime())); ps.setDate(6, new java.sql.Date(df.parse("3/11/2000").getTime())); ps.setInt(1, 3); ps.setString(2, "Programador"); ps.setDouble(3, 15000); ps.setTime(4, new Time(tf.parse("18:00").getTime())); ps.executeUpdate(); System.out.println("Puestos agregados."); ps.close(); ps = c.prepareStatement("INSERT INTO Evento " + "(nombre, fechaYHora) VALUES (?, ?)", Statement.RETURN_GENERATED_KEYS); ps.setString(1, "Bautizo"); ps.setTimestamp(2, new Timestamp(tsf.parse("7/3/2009 9:00").getTime())); int agregados = ps.executeUpdate(); rs = ps.getGeneratedKeys(); rs.next(); System.out.println("Eventos agregados: " + agregados + "."); System.out.println("Llave generada: " + rs.getInt(1) + "."); } finally { if (rs != null) { try { rs.close(); } catch (SQLException e) {} } if (ps != null && !ps.isClosed()) { try { ps.close(); } catch (SQLException e) {} } if (c != null) { c.close(); } } }}

Ejemplo de modificación:123

import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;

17 / 27

Page 18: introjdbc

Introducción a JDBC

456789

1011121314151617181920212223242526272829303132

import java.sql.SQLException;

public class AumentoDeSueldo { public static void main(String[] args) throws ClassNotFoundException, SQLException { Class.forName("org.apache.derby.jdbc.EmbeddedDriver"); Connection c = null; PreparedStatement ps = null; try { c = DriverManager.getConnection("jdbc:derby:eventos", "", ""); ps = c.prepareStatement("UPDATE Puesto " + "SET sueldoMensual = sueldoMensual + ? " + "WHERE clave = ?"); ps.setDouble(1, 300.00); ps.setInt(2, 1); int modificados = ps.executeUpdate(); System.out.println("Empleados modificados: " + modificados); } finally { if (ps != null) { try { ps.close(); } catch (SQLException e) {} } if (c != null) { c.close(); } } }}

Ejemplo de consulta:123456789

1011121314151617181920

import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.text.ParseException;

public class ConsultaParametros { public static void main(String[] args) throws ClassNotFoundException, SQLException, ParseException { Class.forName("org.apache.derby.jdbc.EmbeddedDriver"); Connection c = null; PreparedStatement ps = null; ResultSet rs = null; try { c = DriverManager.getConnection("jdbc:derby:eventos", "", ""); ps = c.prepareStatement("SELECT * FROM Sala WHERE nombre = ? "); ps.setString(1, "Cool"); rs = ps.executeQuery(); if (rs.next()) {

18 / 27

Page 19: introjdbc

Introducción a JDBC

2122232425262728293031323334353637383940414243

System.out.println("Nombre: " + rs.getString("nombre")); System.out.println( "Descripción: " + rs.getString("descripcion")); } else { System.out.println("Sala no encontrada"); } } finally { if (rs != null) { try { rs.close(); } catch (SQLException e) {} } if (ps != null) { try { ps.close(); } catch (SQLException e) {} } if (c != null) { c.close(); } } }}

1.10. Generación Automática y Recuperación de Llaves.Algunas aplicaciones requieren generar automáticamente claves y detectar cual es el valor de estas. Debe  hacerse   al  momento  de   insertar   los   datos,   pues   si   las   claves   se   reservaran   al  momento  de desplegar la forma, y muchos usuarios tienen abierta la misma ventana, a cada uno de ellos se le asigna una clave diferente; si algunos no guardan sus datos, se pueden desperdiciar muchos valores de la clave. Hay dos formas de realizar esta función, dependiendo de la base de datos.

Generación y Recuperación de Llaves con MySQL y Derby.Ambas bases de datos tienen la forma de declarar campos con valores generados automáticamente.

Para Derby es de la siguiente forma:

1234

CREATE TABLE TipoDeProducto ( tprod_clave INTEGER PRIMARY KEY GENERATED ALWAYS AS IDENTITY, tprod_nombre VARCHAR(30) UNIQUE NOT NULL)

19 / 27

Page 20: introjdbc

Introducción a JDBC

Para MySQL es así:

12345

CREATE TABLE TipoDeProducto ( tprod_clave INTEGER PRIMARY KEY AUTO_INCREMENT, tprod_nombre VARCHAR(30) UNIQUE NOT NULL)TYPE = InnoDBCHARACTER SET utf8 COLLATE utf8_spanish_ci;

Cuando se inserta un dato, hay que indicar que se espera recuperar las llaves generadas:1234

// Inserta el objeto en la tabla y solicita que se capture// la llave generada automáticamente.ps = c.prepareStatement("INSERT INTO TipoDeProducto (tprod_nombre) VALUES (?)", Statement.RETURN_GENERATED_KEYS);

Para recuperar la llave generada, se utiliza el método getGeneratedKeys de la siguiente forma (la variable c es la referencia a una conexión):12345678

int nuevaClave = -1;// Recupera un result set con las llaves generadas.ResultSet rs = ps.getGeneratedKeys();// Si solo se generó una llave, hay un solo renglónif (rs.next()) { // Si solo se generó una llave, está en el primer campo nuevaClave = rs.getInt(1);}

Generación y Recuperación de Llaves con Oracle.En este caso el campo solo debe de ser numérico, sin una declaración especial.

1234

CREATE TABLE TipoDeProducto ( tprod_clave INTEGER PRIMARY KEY, tprod_nombre VARCHAR(30) UNIQUE NOT NULL)

Hay que crear una secuencia.1 CREATE SEQUENCE sec_tprod INCREMENT BY 1 START WITH 1;

Antes de insertar, hay que recuperar el siguiente valor de la secuencia usando la instrucción nextval. En el siguiente ejemplo, s es una referencia a un Statement.1234567

ResultSet rs = s.executeQuery("SELECT sec_tprod.nextval FROM DUAL");int nuevaClave = -1;// Si solo se generó una llave, hay un solo renglónif (rs.next()) { // Si solo se generó una llave, está en el primer campo nuevaClave = rs.getInt(1);}

20 / 27

Page 21: introjdbc

Introducción a JDBC

Lo único que resta es insertar en la tabla usando el nuevo valor123

ps = c.prepareStatement("INSERT INTO TipoDeProducto(tprod_clave, tprod_nombre)” + “ VALUES (?, ?)");ps.setInt(1, nuevaClave);

Ejemplo:123456789

1011121314151617181920212223242526272829303132333435363738394041

import java.sql.Connection;import java.sql.DriverManager;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;

public class LlaveGenerada { public static void main(String[] args) throws ClassNotFoundException, SQLException { Class.forName("org.apache.derby.jdbc.EmbeddedDriver"); Connection c = null; Statement s = null; ResultSet rs = null; try { c = DriverManager.getConnection("jdbc:derby:eventos", "", ""); s = c.createStatement(); int agregados = s.executeUpdate("INSERT INTO Evento " + "(nombre, fechaYHora) " + "VALUES ('15 años', {ts '2009-04-01 21:00:00'})", Statement.RETURN_GENERATED_KEYS); rs = s.getGeneratedKeys(); rs.next(); System.out.println("Eventos agregados: " + agregados + "."); System.out.println("Llave generada: " + rs.getInt(1) + "."); } finally { if (rs != null) { try { rs.close(); } catch (SQLException e) {} } if (s != null) { try { s.close(); } catch (SQLException e) {} } if (c != null) { c.close(); } } }}

21 / 27

Page 22: introjdbc

Introducción a JDBC

1.11. Procedimientos Almacenados.Algunos manejadores de bases de datos permiten crear funciones que manipulan tablas e invocarlas desde programas. Se conocen como procedimientos almacenados. No todos los manejadores soportan esta característica.

Los   objetos   que   implementan   la   interfaz  java.sql.CallableStatement  (derivada   de java.sql.PreparedStatement) pueden invocar los procedimientos almacenados. Dado que la forma de invocación cambia según el manejador, se utiliza una secuencia de escape especial.  Hay cuatro formas de especificarla que dependen del uso u omisión de parámetros, y de la devolución de valores. Son las siguientes:

{call procedimiento}

Para un procedimiento almacenado que no devuelve valores ni recibe parámetros.

{? = call procedimiento}

Para un procedimiento almacenado que devuelve un valor (que se maneja como el primer parámetro) y no recibe parámetros.

{call procedimiento(?, ?, ...)}

Para un procedimiento almacenado que no devuelve valores y recibe uno o más parámetros.

{? = call procedimiento(?, ?, ...)}

Para un procedimiento almacenado que devuelve un valor (que se maneja como el primer parámetro) y recibe uno o más parámetros.

En   el   siguiente   ejemplo   se   crea   una   instancia   de  CallableStatement,   se   le   asigna   valor   a   sus parámetros y se invoca.

// Declara la invocación a suma.CallableStatement cs = c.prepareCall("{? = call suma(?, 5) }");// Declara el parámetro de salida que corresponde al valor de regreso.cs.registerOutParameter(1, Types.INTEGER);//Declara el parámetro 2, que corresponde al primer argumento de la invocación.cs.setInt(2, 3);// Invoca el procedimiento.cs.executeUpdate();// Obtiene el valor devuelto.

22 / 27

Page 23: introjdbc

Introducción a JDBC

int x = cs.getInt(1);// Cierra el objeto.cs.close();

Cuando la invocación devuelve un java.sql.ResultSet y se desea recorrerlo hacia adelante y hacia atrás, también se puede crear la invocación de la siguiente forma:

CallableStatement cs = c.prepareCall("{call consultaProveedores}", ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);

Hay tres tipos de parámetros, que se marcan con signos de interrogación en la secuencia de escape, de la misma forma que en una instancia de java.sql.PreparedStatement.

● IN.  De entrada. Reciben información del programa. Se declaran de la misma forma que los parámetros de java.sql.PreparedStatement, usando setXX, como en este ejemplo:

cs.setInt(1, 4);

● OUT.  De salida. Regresan información al programa. El valor devuelto por el procedimiento almacenado   es   de   este   tipo.   Se   declaran   con   el   método    registerOutParameter  de java.sql.CallableStatement, como se muestra:

cs.registerOutParameter(1, Types.INTEGER);

Los   valores   posibles   de   la   clase  java.sql.Types  son   los   siguientes:   BIT,   TINYINT, SMALLINT, INTEGER, BIGINT, FLOAT, REAL, DOUBLE, NUMERIC, DECIMAL, CHAR, VARCHAR,   LONGVARCHAR,   DATE,   TIME,   TIMESTAMP,   BINARY,   VARBINARY, LONGVARBINARY, NULL, OTHER, JAVA_OBJECT, DISTINCT, STRUCT, ARRAY, BLOB, CLOB, REF, DATALINK, BOOLEAN, ROWID, NCHAR, NVARCHAR, LONGNVARCHAR, NCLOB y SQLXML.

Después de la ejecución del procedimiento, los valores devueltos se recuperan con operaciones getXXX(número), como en el caso de java.sql.ResultSet. Así por ejemplo, el parámetro 1, declarado de salida, de tipo entero se recupera con.

int x = cs.getInt(1);

● INOUT. De entrada y salida. Intercambia información en los dos sentidos con el programa. Se declaran   dos   veces:   una   como   como   IN   y   otra   como   OUT.   Después   de   la   ejecución   del 

23 / 27

Page 24: introjdbc

Introducción a JDBC

procedimiento, los valores devueltos se recuperan con operaciones getXXX(número), como en el caso de java.sql.ResultSet.

Cuando el cuerpo de un procedimiento almacenado utiliza la instrucción SELECT de SQL se invoca con  executeQuery.  Se recomienda que  los  registros devueltos  se  procesen antes  de  leer  cualquier parámetro de entrada.

No todos los manejadores de bases de datos soportan procedimientos almacenados.

Ejemplo de Procedimientos Almacenados en MySQL.123456789

1011121314151617181920212223242526272829303132333435363738

CREATE DATABASE Procedimientos;USE Procedimientos;/* Define la nuevo cadena para separar instrucciones, que ahora es // */DELIMITER ///* Crea la tabla*/CREATE TABLE Conocido ( con_clave INTEGER PRIMARY KEY, con_nombre VARCHAR(100), con_telefono VARCHAR(50) NOT NULL, con_email VARCHAR(50) NOT NULL, con_fecha DATE NOT NULL, con_direccion LONG VARCHAR NOT NULL)///* Inserta datos. */INSERT INTO Conocido (con_clave, con_nombre, con_telefono,con_email, con_fecha, con_direccion) VALUES(1, 'Zoila Vaca', '01-800-MUU', '[email protected]', '2003-10-3', 'Establos #23'), (2, 'Rolando Mota', '01-800-VIAJE', '[email protected]', '2005-11-6', 'Misterios #12')///* Define un procedimento almacenado que suma datos. */CREATE FUNCTION suma (a INTEGER, b INTEGER) RETURNS INTEGERRETURN a + b;///* Define un procedimento almacenado que cuenta los conocidos. */CREATE PROCEDURE cuenta (OUT total INT)BEGIN SELECT COUNT(*) INTO total FROM Conocido;END///* Define un procedimento inserta un conocido. */CREATE PROCEDURE insertaConocido (clave INTEGER, nombre CHAR(100), telefono CHAR(50), email CHAR(50), fecha DATE, direccion TEXT)BEGIN INSERT INTO Conocido (con_clave, con_nombre, con_telefono,con_email, con_fecha, con_direccion) VALUES(clave, nombre, telefono, email, fecha, direccion);END

24 / 27

Page 25: introjdbc

Introducción a JDBC

39404142434445464748

///* Define un procedimento almacenado que devuelve todos los conocidos. */CREATE PROCEDURE consultaConocidos ()BEGIN SELECT * FROM Conocido;END//GRANT ALL PRIVILEGES ON Procedimientos.* TO 'usu'@localhost IDENTIFIED BY 'ario'//

Ejemplo de Invocación desde Java:123456789

101112131415161718192021222324252627282930313233343536373839

import java.sql.CallableStatement;import java.sql.Connection;import java.sql.Date;import java.sql.DriverManager;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Types;import java.text.ParseException;import java.text.SimpleDateFormat;

public class ProcedimientosAlmacenados { public static void main(String[] args) throws ClassNotFoundException, ParseException, SQLException { Class.forName("com.mysql.jdbc.Driver"); /* En este caso la opción noAccessToProcedureBodies indica que * esta conexión no tiene suficientes permisos para obtener el * código del procedimiento almacenado. */ String url = "jdbc:mysql://localhost/Procedimientos" + "?noAccessToProcedureBodies=true"; String usuario = "usu"; String password = "ario"; Connection c = null; CallableStatement cs1 = null; CallableStatement cs2 = null; CallableStatement cs3 = null; CallableStatement cs4 = null; ResultSet rs = null; try { /* Crea un formato para fecha. * dd - dia del mes. * MM - mes en dos dígitos. * yyyy - año en cuatro dígitos. * / - separación. */ SimpleDateFormat fmt = new SimpleDateFormat("dd/MM/yyyy"); c = DriverManager.getConnection(url, usuario, password); // Declara la invocación a suma. cs1 = c.prepareCall("{? = call suma(?, 5) }"); /* Declara el parámetro de salida que corresponde al valor de * regreso. */

25 / 27

Page 26: introjdbc

Introducción a JDBC

40414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091

cs1.registerOutParameter(1, Types.INTEGER); /* Declara el parámetro 2, que corresponde al primer argumento de * la invocación. */ cs1.setInt(2, 3); // Invoca el procedimiento. cs1.executeUpdate(); // Obtiene el valor devuelto. System.out.println("suma(3, 5) = " + cs1.getInt(1)); // Declara la invocación a cuenta. cs2 = c.prepareCall("{call cuenta(?) }"); // Declara el parámetro de salida al total de registros. cs2.registerOutParameter(1, Types.INTEGER); cs2.executeUpdate(); // Obtiene el valor devuelto. System.out.println("total de conocidos = " + cs2.getInt(1)); // Declara la invocación a insertaConocido. cs3 = c.prepareCall("{call insertaConocido" + "(?, ?, ?, ?, ?, ?) }"); // Declara los parámetros de entrada. cs3.setInt(1, 3); cs3.setString(2, "Armando Pacheco"); cs3.setString(3, "01-800-TQUILA"); cs3.setString(4, "[email protected]"); cs3.setDate(5, new Date(fmt.parse("23/2/2007").getTime())); cs3.setString(6, "Noche de Ronda #99"); cs3.executeUpdate(); // Declara la invocación a consultaConocido. cs4 = c.prepareCall("{call consultaConocidos}"); rs = cs4.executeQuery(); while (rs.next()) { // Muestra el contenido del registro. System.out.println(rs.getInt("con_clave") + " | " + rs.getString("con_nombre") + "|" + rs.getString("con_telefono") + "|" + rs.getString("con_email") + "|" + rs.getString("con_direccion") + "|" + fmt.format(rs.getDate("con_fecha"))); } } finally { if (rs != null) { try { rs.close(); } catch (SQLException e) {} } if (cs1 != null) { try { cs1.close(); } catch (SQLException e) {} } if (cs2 != null) { try { cs2.close();

26 / 27

Page 27: introjdbc

Introducción a JDBC

9293949596979899100101102103104105106107108109110111

} catch (SQLException e) {} } if (cs3 != null) { try { cs3.close(); } catch (SQLException e) {} } if (cs4 != null) { try { cs4.close(); } catch (SQLException e) {} } if (c != null) { try { c.close(); } catch (SQLException e) {} } } }}

27 / 27