¡Acceso ilimitado 24/7 a todos nuestros libros y vídeos! Descubra la Biblioteca Online ENI. Pulse aquí
¡Acceso ilimitado 24/7 a todos nuestros libros y vídeos! Descubra la Biblioteca Online ENI. Pulse aquí
  1. Libros
  2. Desarrollo informático
  3. JDBC
Extrait - Desarrollo informático Aprenda a diseñar antes de programar
Extractos del libro
Desarrollo informático Aprenda a diseñar antes de programar Volver a la página de compra del libro

JDBC - Mapping Objeto/Relacional

Objetivos del capítulo

  • Desarrollar aplicaciones que accedan a una base de datos relacional.

  • Desarrollar las clases necesarias para el mapping objeto-relacional (se trata de establecer una correspondencia entre las tablas de una base de datos relacional y los objetos utilizados para acceder a la base).

Definición

El API JDBC (Java DataBase Connectivity) es un conjunto de clases e interfaces Java, que permiten el acceso a los datos.

Aunque el API JDBC permita el acceso a cualquier fuente de datos, principalmente se utiliza para acceder a las bases de datos relacionales.

Comunicación Java - Base de datos

1. Controladores (drivers) JDBC

Para conectarse a una base de datos, JDBC necesita clases particulares escritas por el editor de la base de datos. Estas clases se agrupan en un controlador (driver). Es un archivo .jar (Java archivo).

El API JDBC proporciona interfaces, que los controladores deben implementar obligatoriamente.

Esto tiene dos ventajas:

  • Las interfaces exponen los métodos que podemos utilizar.

  • Es posible utilizar estos métodos sin conocer el nombre de la clase correspondiente del controlador. Este nombre es diferente según el editor básico de datos.

2. Esquema de comunicación

images/1_214.png

Trabajar con JDBC

1. Ejecución de una consulta SQL de tipo SELECT

Escribir un programa Java que acceda a una base de datos implica:

  • Cargar el controlador de la base de datos utilizada.

  • Establecer una conexión a la base. Hay que cerrar la conexión después de su utilización. 

  • Crear un objeto Statement (objeto de tratamiento). Hay que cerrar el Statement después de su utilización.

  • Ejecutar los consultas SQL.

  • Si la consulta es una SELECT, devuelve un objeto ResultSet, que contiene las filas y las columnas seleccionadas. Hay que cerrar el ResultSet después de su utilización.

2. Estructura general del programa para una consulta SELECT

El «esqueleto» del siguiente programa muestra cómo cerrar con seguridad la conexión, el Statement y el ResultSet. Cada apertura o creación exitosa se sigue por un bloque try con un finally de cierre de los objetos:

Cambiar el controlador de la base de datos  
  
Establecer una conexión a la base (objeto Connection)  
try  
{  
   Crear un objeto Statement  
   try  
   {  
       Ejecutar una SELECT: devuelve un objeto ResultSet  
       try  
       {  
           Utilizar el ResultSet  
       }  
       finally  
       {  
           Cerrar el ResultSet  
       }  
   }  
   finally  
   {  
       cerrar el Statement  
   }  
}  
finally  
{  
   Cerrar la conexión  
} 

Cuando cierra la conexión, el Statement y el ResultSet siguen estando referenciados, pero no son utilizables. Es importante cerrar el ResultSet y el Statement para recuperar el espacio ocupado por estos objetos que ya no son útiles.

3. Ejemplo: base de datos utilizada

  • El sistema de gestión básico de datos utilizado es MySQL.

  • La base de datos se llama «gnmi».

  • El nombre de usuario y la contraseña...

Presentación de las clases herramientas

En el paquete herramientasMG.jdbc se encuentran las clases que pueden facilitar el desarrollo.

1. JuegoResultado

a. Clase JuegoResultado

El método executeQuery() de la interfaz Statement devuelve un objeto de tipo ResultSet.

Un ResultSet está unido a la conexión. Cuando se cierra la conexión, se pierde el ResultSet. Normalmente es interesante conservar los resultados leídos después de haber cerrado la conexión.

La clase JuegoResultado permite volver a copiar la información del ResultSet. A continuación podemos cerrar la conexión, intentando preservar los valores leídos.

Esta copia organiza los datos leídos en dos colecciones:

  • Una colección de objetos Columna (la clase Columna es la del paquete herramientasMG.varios). 

  • Una colección de filas (Vector<Vector<Object>>).

Uno de los constructores de la clase JuegoResultado recibe como argumento un ResultSet, que vuelve a copiar las dos colecciones.

Gracias a esta organización de datos, la utilización de la clase JuegoResultado es más agradable y sencilla que la del ResultSet. ¡Pero tenemos derecho a que nos gusten los next()!

public class JuegoResultado implements java.io.Serializable  
{  
   private Vector<Columna> columnas;  
   private Vector<Vector<Object>> filas;  
  
   public JuegoResultado()  
   {  
   }  
  
   public JuegoResultado(ResultSet rs) throws SQLException  
   {  
       . . .  
   }  
  
   . . .  
     
   public Vector<Columna> getColumnas()  
   {  
       return columnas;  
   }  
  
   public Vector<Vector<Object>> getFilas()  
   {  
       return filas;  
   }  
  
   . . .  
} 

b. Ejecución de una consulta SQL de tipo SELECT con JuegoResultado

public class VerificaJdbcSqlJuegoResultado  
{  ...

Trabajo práctico: Proyecto GestionContactoJdbc - Versión 1

1. Objetivo

  • Utilizar JDBC para acceder a una base de datos.

  • Modificar el Modelo de la aplicación GestionContactoLocal para permitir este acceso. Adaptar el Controlador. Conservar la Vista sin modificación.

2. Arquitectura del proyecto: 2 tiers

images/7_214.png

3. Tema

Retomar la aplicación GestionContactoLocal del capítulo JTable - DAO - MVC.

  • Modificar la clase ContactoDAO para leer los datos «Contacto» en las tablas CONTACTO de la base de datos gnmi (usuario UTIL_BIP, contraseña x).

  • Si la lectura de la base de datos provoca una excepción, mostrar el mensaje de error en una caja de diálogo (JOptionPane).

  • Durante el cierre de la ventana interna contacto, no cambiar nada respecto al proyecto GestionContactoLocal. No reportar las modificaciones a la base de datos. 

4. Diseño

Completar el diagrama de secuencia de la aplicación GestionContactoLocal.

5. Programación

Modificar las clases ContactoDAO y Controlador.

Todas las clases de la vista se utilizan sin modificación.

6. GestionContactoJdbc - Versión 1: propuesta de corrección

a. Diagrama de secuencia

images/Esquema2.png

Tratamiento de excepciones:

La lectura de datos en la base de datos puede fallar por varias razones, técnicas o de software (problemas de autorizaciones, consulta SQL incorrecta, servidor fuera de servicio, etc.). El método executeQuery() puede desencadenar una excepción de tipo SQLException.

¿A quién se debe informar de estos errores? Es al usuario de la aplicación, debido a que el controlador prevé una alternativa en respuesta a la petición del usuario. El método muestraContactos() envía la lista de los contactos y de las columnas para que se visualicen en la ventana...

JDBC: complementos

1. Tabla utilizada en los ejemplos

a. Script SQL de creación de la tablas EMPLEADO

drop tablas EMPLEADO;  
  
create tablas EMPLEADO  
(  
   EMPNUM                          smallint primary key not null,  
   EMPNOM                          varchar(20) null,  
   EMPSAL                          dec(9,2) null,  
   EMPDAT                          datetime null  
);  
  
create unique index EMPLEADO_PK on EMPLEADO(EMPNUM); 

b. Script SQL de proceso de llenado de la tabla EMPLEADO

delete from empleado;  
insert into empleado values(1, ‘PEDRO', NULL, ‘2016/04/25');  
insert into empleado values(4, ‘Alcaudón', 2214, NULL);  
insert into empleado values(10, ‘Pivert', 1811, ‘2015/11/05');  
  
select * from empleado; 

2. Ejecución de consultas INSERT y DELETE

public class VerificaInsert  
{  
   public static void main(String args[]) throws IOException  
   {  
       . . .  
       try  
       {  
           Class.forName("com.mysql.jdbc.Driver");  
  
           base = new BaseDeDatos(  
               "jdbc:mysql://localhost/gnmi?user=util_bip&password=x");  
           accesoBase = new AccesoBase(base);  
  
           try  
           {  
               accesoBase.getConnection();  
  
               try  
               {  
       ...

El Mapping Objeto/Relacional

1. Exposición del problema que hay que resolver

Se trata de realizar las entradas/salidas entre una base de datos relacional y los objetos ubicados en memoria.

A continuación se muestra un esquema general de las entradas/salidas (lecturas/escrituras): 

images/11_214.png
  • Leer la información consiste en transferir la información del disco a una zona de memoria prevista para recibirlos. Esta zona de memoria debe ser tan grande como para contener la información leída.

  • Escribir la información consiste en volver a copiar la información contenida en la zona de memoria, en el disco duro.

En el caso de una base de datos relacional, los datos almacenados en el disco se organizan en forma de tablas. Cada tabla está formada por filas y columnas.

Ejemplo

Tabla CONTACTO

images/12_214.png

Estas tablas contienen cinco columnas: NUMERO, NOMBRE, DIRECCION, CODIGO_POSTAL Y CIUDAD.

Contiene tres filas correspondientes a los contactos: 100, 101, 102.

Leer una fila de la tabla hace necesario reservar un espacio en memoria. En el caso de un lenguaje-objeto, hay que instanciar un objeto de una clase.

El siguiente esquema UML indica que la clase Contacto tiene propiedades correspondientes a cada columna de la tabla CONTACTO: numero, nombre, direccióncodigoPostal y ciudad.

images/13_214.png

El numero, que identifica de manera única al contacto, se llama clave primaria.

A continuación se muestra el código Java de la clase Contacto:

public class Contacto  
{  
  ...

Trabajo práctico: Proyecto Mapping

1. Objetivo

Encontrar un enfoque sistemático de diseño y de escritura de las clases, necesarias para el mapping objeto/relacional.

2. Tema

  • Diseñar y escribir las clases Contacto, ContactoDAO, Sector, SectorDAO, PagoPagoDAO necesarias para leer y escribir los objetos Java a partir de una base de datos relacional, cuya descripción se da por su MCD.

  • Podemos comenzar diseñando las clases Contacto y ContactoDAO del proyecto, y después generalizar a los sectores y pagos.

  • En la clase Contacto, se trata de leer (get) y modificar (set) todas las propiedades de la clase.

  • En la clase ContactoDAO, se trata de prever todos los accesos a la base (select, update, insert, delete) y algunos métodos de generación de las listas de objetos Contacto.

3. Documentos adjuntos

Las siguientes secciones presentan:

  • El MCD del proyecto Mapping.

  • El diagrama de clases del proyecto Mapping.

  • El controlador de una aplicación de comprobación que utiliza las clases que se han de desarrollar.

En el paquete herramientasMG.varios, existe una clase Conversion que tiene un método cadenaSQL() que permite convertir una cadena de caracteres al formato SQL (problema de comillas simples). También hay un método dateSQL().

a. Modelo Conceptual de Datos (MCD) del proyecto Mapping

images/21_214.png
  • Un sector puede tener varios contactos.

  • Un contacto pertenece a un sector y puede tener varios pagos.

  • Un pago pertenece a un contacto.

b. Diagrama de clases (UML) del proyecto Mapping

images/22_214.png

Este diagrama representa las mismas reglas de gestión que el MCD. Atención, entre Merise y UML, porque las cardinalidades están invertidas.

El modelo conceptual de datos de Merise representa las tablas de la base de datos. El diagrama UML representa los objetos en memoria. Esta diferenciación es práctica y visual. Por supuesto, es posible representar todo en UML. Pero como tenemos las dos representaciones, podemos aprovecharlas...

c. Controlador de la aplicación de verificación

public class Controlador  
{  
   private static BaseDeDatos base;  
   private static AccesoBase accesoBase;  
  
   public static void main(String args[])  
   {  
       Contacto contacto;  
       Pago pago;  ...

Trabajo práctico: Proyecto GestionContactoJdbc

1. Objetivos

  • Utilizar los paquetes de las clases desarrolladas en el TP Mapping.

  • Guardar las modificaciones en la base de datos.

2. Tema

  • Modificar la aplicación «GestionContactoJdbc - versión 1» para permitir el registro de las modificaciones de los contactos en la base de datos durante el cierre de la ventana interna de los contactos.

  • Sustituir las clases Contacto y ContactoDAO por las de los paquetes businessMapping y daoJdbcMapping.

  • El paquete businessMapping contiene las clases Contacto, Sector, Pago.

  • El paquete daoJdbcMapping contiene las clases ContactoDAO, SectorDAO y PagoDAO.

  • Transmitir la lista de los Sectores a la ventana interna de los contactos para adaptar la lista desplegable de introducción de datos del código de sector.

images/23_213.png

3. GestionContactoJdbc: Proposición de corrección

a. Clase Controlador

public class Controlador  
{  
   . . .  
  
   public static void main(String args[])  
   {  
       . . .  
       contactoDAO = new ContactoDAO(accesoBase);  
       sectorDAO = new SectorDAO(accesoBase);  
       . . .  
   }  
  
   public static void solicitaContactos()  
   {  
       Vector<Contacto> listaContactos;  
       Vector<Columna> listaColumnas;  
       Vector<Sector> listaSectores;  
  
       try  
       {  
           accesoBase.getConnection();  
  
           try  
           {  
               listaContactos = contactoDAO.leerLista();  
               listaColumnas = contactoDAO.getListaColumnas();  
               ...