Ejemplo: Crear los DAO (parte 2)

Hecha la estructura de clases de los DAO queda por crear el código propio que ejecuta las statements de MySQL a partir de los objetos propios. En este vídeo os enseño cómo hacer este mapeo.

Hay una versión nueva de este curso. Haz clic aquí para revisar JDBC, la versión actualizada de este curso.

Cuando nos adentramos en la implementación de DAOs para manejar bases de datos MySQL con Java, uno de los primeros pasos fundamentales es dotar a nuestros DAOs de la capacidad para ejecutar sentencias SQL de forma segura y eficiente. Para ello, es imprescindible que cada DAO tenga acceso a una conexión de base de datos, la cual recibiremos a través de un constructor que almacenará esta conexión internamente. Esto nos permitirá reutilizar la conexión y mantener un control centralizado sobre ella.

Sin embargo, no queremos que los DAOs estén dispersos por todo el código ni que tengamos que crearlos manualmente cada vez que los necesitemos. Por eso, diseñaremos un gestor que se encargue de crear y administrar los DAOs, manteniendo la conexión y devolviendo instancias específicas cuando las solicitemos, como por ejemplo un DAO para alumnos o para matrículas. Este gestor será responsable de encapsular la lógica de creación y cierre de conexiones, facilitando así el uso de los DAOs desde otras partes de la aplicación.

Un detalle interesante es que este patrón DAO no está limitado exclusivamente a bases de datos SQL. Podemos imaginar implementaciones que trabajen con listas en memoria, como un ArrayList, donde los métodos de insertar, modificar, eliminar y obtener simplemente manipulan la estructura de datos subyacente. Por ello, las excepciones que manejaremos no serán las típicas SQLException, sino nuestras propias excepciones personalizadas, como una DAOException, que nos permitirán abstraer la fuente de datos y manejar errores de forma uniforme.

Para comenzar a implementar los métodos de los DAOs, lo primero es definir las sentencias SQL que vamos a utilizar. Por ejemplo, para insertar un alumno en la tabla alumnos, la sentencia sería algo así:

insert into alumnos (id_alumno, nombre, apellidos, fecha_nac) values (?, ?, ?, ?)

Usamos signos de interrogación para indicar los parámetros que luego asignaremos mediante un PreparedStatement. De esta forma, evitamos problemas de inyección SQL y delegamos en el driver la correcta gestión de los tipos de datos.

De manera similar, para actualizar un alumno, la sentencia sería:

update alumnos set nombre = ?, apellidos = ?, fecha_nac = ? where id_alumno = ?

Es fundamental no olvidar el where para evitar modificar todos los registros accidentalmente.

Para eliminar un alumno, la sentencia es:

delete from alumnos where id_alumno = ?

Y para obtener todos los alumnos:

select id_alumno, nombre, apellidos, fecha_nac from alumnos

Aunque en este último caso, si la tabla es muy grande, conviene implementar paginación con limit y offset para no saturar la memoria.

Al implementar el método de inserción en Java, partimos de la conexión que tenemos y creamos un PreparedStatement con la sentencia de inserción. Luego, asignamos los valores de los parámetros usando los métodos adecuados según el tipo de dato. Por ejemplo, para un identificador de tipo long usamos setLong, para cadenas setString, y para fechas setDate. En el caso de las fechas, debemos convertir las fechas de Java a java.sql.Date, que es el tipo que entiende el driver JDBC.

Un ejemplo de cómo asignar los parámetros sería:

PreparedStatement stat = null;
try {
    stat = con.prepareStatement(INSERT);
    stat.setLong(1, alumno.getId());
    stat.setString(2, alumno.getNombre());
    stat.setString(3, alumno.getApellidos());
    stat.setDate(4, new java.sql.Date(alumno.getFechaNacimiento().getTime()));
    int filasInsertadas = stat.executeUpdate();
    if (filasInsertadas == 0) {
        throw new DAOException("No se pudo insertar el alumno");
    }
} catch (SQLException ex) {
    throw new DAOException("Error en SQL", ex);
} finally {
    if (stat != null) {
        try {
            stat.close();
        } catch (SQLException ex) {
            // Manejo del error al cerrar el statement
        }
    }
}

Aquí, además de preparar y ejecutar la sentencia, comprobamos que la operación afectó al menos una fila, y en caso contrario lanzamos una excepción personalizada. También nos aseguramos de cerrar el PreparedStatement en un bloque finally para liberar recursos.

Para manejar las excepciones de forma coherente, definimos una clase DAOException que extiende de Exception y que puede envolver excepciones SQL originales, facilitando así el manejo de errores en capas superiores sin exponer detalles específicos de la base de datos.

Este patrón se repetirá para los demás métodos CRUD, adaptando las sentencias SQL y los parámetros según corresponda. Aunque puede parecer laborioso, esta estructura nos proporciona un código limpio, seguro y fácil de mantener.

Finalmente, para no tener que crear y cerrar conexiones y DAOs manualmente, construiremos un singleton gestor que mantenga la conexión y nos proporcione los DAOs necesarios, encapsulando toda esta lógica y facilitando su uso desde cualquier parte de la aplicación. Así, tendremos un sistema modular y escalable para interactuar con la base de datos.

Lista de reproducción
  1. 1
    Presentación de JDBC
    4 minutos
  2. 2
    Instalando MySQL
    7 minutos
  3. 3
    Creando tablas
    9 minutos
  4. 4
    Agregando el driver JAR
    7 minutos
  5. 5
    Estableciendo la conexión
    8 minutos
  6. 6
    Statement y ResultSet
    9 minutos
  7. 7
    Bobby Tables y PreparedStatement
    8 minutos
  8. 8
    Transacciones y MySQL
    6 minutos
  9. 9
    Transacciones, commits y rollbacks (parte 1)
    7 minutos
  10. 10
    Transacciones, commits y rollbacks (parte 2)
    6 minutos
  11. 11
    Ejemplo: Crear modelos
    9 minutos
  12. 12
    Ejemplo: Crear los DAO (parte 1)
    10 minutos
  13. 13
    Ejemplo: Crear los DAO (parte 2)
    12 minutos
  14. 14
    Ejemplo: Crear los DAO (parte 3)
    13 minutos
  15. 15
    Ejemplo: DAO Manager
    12 minutos
  16. 16
    Ejemplo: CRUD Alumnos (parte 1)
    15 minutos
  17. 17
    Ejemplo: CRUD Alumnos (parte 2)
    14 minutos
  18. 18
    Ejemplo: CRUD Alumnos (parte 3)
    13 minutos
  19. 19
    Ejemplo: CRUD Profesores
    25 minutos
  20. 20
    Ejemplo: CRUD Asignaturas
    alrededor de 1 hora
  21. 21
    Ejemplo: Login (final adelantado)
    17 minutos
  22. 22
    Conectar a PostgreSQL en Java con JDBC
    8 minutos
  23. 23
    Conectar a PostgreSQL en Kotlin con JDBC
    7 minutos
  24. 24
    Conectar a PostgreSQL en Java con JDBC (con NetBeans)
    10 minutos