Skip to content

08. JDBC (Java Database Connectivity)

Melissa Diaz edited this page Feb 20, 2025 · 3 revisions

JDBC

(Java Database Connectivity)

¿Qué es JDBC?
JDBC es una API estándar de Java que permite conectar aplicaciones Java con bases de datos relacionales. Proporciona una forma unificada de ejecutar consultas SQL y procesar resultados sin depender de un DBMS específico, siempre que se disponga del driver adecuado.

Componentes principales de JDBC

  1. JDBC Driver Manager → Carga el driver de la base de datos y gestiona la conexión.
  2. API JDBC → Proporciona las interfaces y clases necesarias para interactuar con bases de datos.

📌 Paquetes importantes

  • java.sql.* (uso general de JDBC)
  • javax.sql.* (soporte avanzado, como pooling de conexiones)

📌 Clases e interfaces clave

  • DriverManager → Administra los drivers JDBC.
  • Connection → Representa la conexión con la base de datos.
  • Statement → Ejecuta consultas SQL.
  • PreparedStatement → Mejora seguridad y rendimiento en consultas parametrizadas.
  • ResultSet → Almacena y gestiona los resultados de una consulta SQL.
  • DataSource → Alternativa para manejar conexiones en aplicaciones empresariales.

Conexión a la Base de Datos con JDBC

Para conectarse a una base de datos, se necesita:
Driver JDBC específico para el DBMS.
URL de conexión (jdbc:mysql://host:puerto/base_de_datos).
Credenciales de acceso (usuario y contraseña).

📌 Ejemplo de conexión a MySQL

Connection connection = null;
try {
    Class.forName("com.mysql.cj.jdbc.Driver"); // Carga el driver
    String url = "jdbc:mysql://localhost:3306/biblioteca"; // URL de conexión
    connection = DriverManager.getConnection(url, "user", "password"); // Conectar
} catch (SQLException ex) {
    ex.printStackTrace();
} 

🔹 Class.forName("com.mysql.cj.jdbc.Driver") → Carga el driver de MySQL.
🔹 DriverManager.getConnection(url, usuario, contraseña) → Establece la conexión.


Uso de JDBC en Maven

En Maven, en pom.xml:

<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <version>9.2.0</version>
</dependency>

Puntos Claves: Componentes de una Conexión JDBC

URL de Conexión (JDBC URL): Define la dirección del servidor, puerto y base de datos. Ejemplo para MySQL:

jdbc:mysql://<host>:<puerto>/<nombre_base_datos>?<opciones>

Credenciales de acceso: Usuario y contraseña necesarios para autenticar la conexión.

Controlador JDBC: Permite la comunicación entre Java y la base de datos. Ejemplo para MySQL:

com.mysql.cj.jdbc.Driver

Configuración de la zona horaria (opcional): Se requiere en algunas bases de datos para evitar errores con fechas y horas.

Manejo de errores y excepciones: Uso de try-catch para manejar SQLException y otros posibles fallos de conexión.

Cierre de la conexión: Importante liberar recursos con close() después de usar la conexión.

Interacción con bases de datos en Java con JDBC

Este capítulo explora cómo conectar y manipular bases de datos en Java usando la API JDBC.

1. Uso del objeto Statement

  • Se crea a partir de una conexión (Connection).
  • Permite ejecutar consultas SQL con métodos como:
    • executeQuery(): Para recuperar datos (SELECT).
    • executeUpdate(): Para modificar datos (INSERT, UPDATE, DELETE).
  • Ejemplo de ejecución de una consulta:
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM Table1");
while (rs.next()) {
	int x = rs.getInt("a");
	String s = rs.getString("b");
	double d = rs.getDouble("c");
	System.out.println("Fila = " + x + " " + s + " " + d);
}

2. Recuperación de datos con ResultSet

  • ResultSet almacena los resultados de una consulta SQL.
  • Se recorre fila por fila con next().
  • Se obtienen valores con métodos como: getInt(), getString(), getDouble(), getDate(), entre otros.
  • Se puede acceder a una columna por nombre o número:
String nombre = rs.getString("nombre");
String nombre2 = rs.getString(2); // Segunda columna

3. Optimización con PreparedStatement

  • Mejora el rendimiento en consultas repetitivas.
  • Permite el uso de parámetros (?) para evitar concatenaciones inseguras.
  • Ejemplo:
PreparedStatement ps = connection.prepareStatement(
	"UPDATE nombreTabla SET campo1 = 'valor' WHERE campo2 > ? AND campo2 < ?"
);
ps.setInt(1, 1200);
ps.setInt(2, 1300);
int n = ps.executeUpdate(); // Ejecuta la consulta

Note

📝 Statement

  • ⚡ Se utiliza para ejecutar sentencias SQL estáticas (sin parámetros).
  • ✅ Ideal para consultas simples que no requieren valores dinámicos.
  • ⚠️ Menos seguro frente a inyección SQL y menos eficiente para consultas repetitivas.

🔒 PreparedStatement

  • 🏗️ Diseñado para ejecutar consultas SQL parametrizadas con marcadores (?).
  • 🔐 Mejora la seguridad al prevenir la inyección SQL.
  • 🚀 Más eficiente, ya que las consultas se precompilan y pueden reutilizarse con distintos valores.
  • 🔄 Facilita la manipulación de datos dinámicos (cadenas, números, fechas).
  • Buena práctica: Usar PreparedStatement siempre que se necesiten parámetros o consultas repetitivas.

📊 ResultSet

  • 🗄️ Almacena y gestiona los resultados de una consulta SQL.
  • 🔍 Permite recorrer los datos recuperados fila por fila de manera ordenada.
  • 📌 Proporciona métodos específicos para acceder a los valores de cada columna.

¿Qué es un patrón de diseño?

Un patrón de diseño es una solución probada para resolver un tipo específico de problema en el desarrollo de software. Su uso permite escribir código bien organizado, legible y mantenible. Además, facilita la reutilización del código y mejora la escalabilidad del proyecto.

En términos generales, los patrones de diseño proporcionan una terminología estándar y un conjunto de buenas prácticas para resolver problemas comunes en el desarrollo de software.


Patrón de diseño DAO (Data Access Object)

El patrón de diseño DAO (Data Access Object) proporciona una capa de abstracción entre la lógica de negocio y el acceso a los datos almacenados en una base de datos. Facilita la separación de responsabilidades y la reutilización del código, permitiendo una gestión más eficiente y mantenible de los datos.

Ventajas del patrón DAO

Separación de responsabilidades → Desacopla la lógica de negocio del acceso a datos, facilitando el mantenimiento y la escalabilidad.
Reutilización de código → Centraliza las operaciones de base de datos (CRUD), permitiendo su uso en distintas partes del proyecto.
Flexibilidad y facilidad para realizar cambios → Si se modifica la fuente de datos o el sistema de almacenamiento, los cambios se concentran en la capa DAO sin afectar otras capas.
Claridad y organización → La estructura en capas mejora la legibilidad y comprensión del código.
Facilita pruebas unitarias → Permite utilizar implementaciones simuladas para testear la lógica de negocio sin depender de una base de datos real.


Clases en la implementación del patrón DAO

El patrón DAO se implementa mediante al menos cuatro tipos de clases principales:

  1. Entidad: Representa una tabla de la base de datos. Sus atributos corresponden a las columnas de la tabla.
  2. Servicio (Business Service): Contiene la lógica de negocio del proyecto. Se encarga de obtener datos desde la base de datos y enviarlos al cliente, o recibir datos desde el cliente y enviarlos al servidor. Por lo general, incluye los métodos CRUD (Create, Read, Update y Delete).
  3. DAO: Actúa como una capa de acceso a datos que oculta la fuente de datos y los detalles técnicos de la consulta. Se encarga de la conexión con la base de datos y la ejecución de las consultas.
  4. EntidadDaoExt: Extiende la clase DAO y genera las consultas SQL (SELECT, INSERT, etc.). También recibe los datos obtenidos y los envía al servicio correspondiente. Esta clase implementa el patrón Data Transfer Object (DTO), que facilita la transmisión de información entre la capa DAO y la capa de negocio.

Clases Entidades

Las clases entidades representan los objetos del mundo real que se almacenan en la base de datos, mapeando sus atributos a columnas de una tabla.

Características:
  • Atributos: Correspondientes a las columnas de la tabla (ej. id, nombre, email).
  • Métodos: Getters y setters para manipular datos, además de métodos específicos de la entidad.
  • Relaciones: Pueden incluir asociaciones como uno a uno, uno a muchos o muchos a muchos.

Relación entre DAO y Clases Entidades

  • DAO: Maneja la persistencia en la base de datos (inserción, consulta, actualización y eliminación).
  • Entidades: Representan los datos que el DAO manipula.

🔹 Ejemplo:
Un UsuarioDAO interactúa con la base de datos para gestionar los registros de la tabla usuarios, utilizando objetos de la clase Usuario.

Note

El patrón DAO organiza y modulariza la gestión del acceso a datos, mejorando la claridad, mantenibilidad y flexibilidad de la aplicación.

Implementación del DAO Abstracto

El DAO abstracto define métodos comunes para interactuar con la base de datos, como consultar, insertar, modificar y eliminar datos. Además, contiene métodos para conectar y desconectar la base de datos.

Ejemplo de clase abstracta DAO

package persistencia;
import java.sql.*;

public abstract class DAO {
    protected Connection conexion = null;
    protected ResultSet resultSet = null;
    protected Statement statement = null;
    private final String HOST = "127.0.0.1";
    private final String PORT = "3306";
    private final String USER = "root";
    private final String PASSWORD = "root";
    private final String DATABASE = "vivero";
    private final String DRIVER = "com.mysql.cj.jdbc.Driver";
    private final String ZONA = "?useUnicode=true&serverTimezone=UTC";

    protected void connectarDataBase() throws SQLException, ClassNotFoundException {
        try {
            Class.forName(DRIVER);
            String url = "jdbc:mysql://" + HOST + ":" + PORT + "/" + DATABASE + ZONA;
            conexion = DriverManager.getConnection(url, USER, PASSWORD);
            System.out.println("Conexión exitosa a la base de datos.");
        } catch (Exception e) {
            throw e;
        }
    }

    protected void desconectarDataBase() throws SQLException {
        try {
            if (resultSet != null) resultSet.close();
            if (statement != null) statement.close();
            if (conexion != null) conexion.close();
        } catch (Exception e) {
            throw e;
        }
    }

    protected void insertarModificarEliminarDataBase(String sql) throws Exception {
        try {
            connectarDataBase();
            statement = conexion.createStatement();
            statement.executeUpdate(sql);
        } finally {
            desconectarDataBase();
        }
    }

    protected void consultarDataBase(String sql) throws Exception {
        try {
            connectarDataBase();
            statement = conexion.createStatement();
            resultSet = statement.executeQuery(sql);
        } catch (SQLException | ClassNotFoundException ex) {
            throw ex;
        }
    }
}

Implementación del DAO Específico para una Entidad

Cada entidad debe tener su propio DAO específico, extendiendo de la clase abstracta DAO. Esto permite personalizar las operaciones CRUD según la entidad y mejorar la organización del código.

Ejemplo: ClienteDAO

package persistencia;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import entidad.Cliente;

public class ClienteDAO extends DAO {
    public void guardarCliente(Cliente cliente) throws Exception {
        if (cliente == null) throw new Exception("El cliente no puede ser nulo");
        String sql = "INSERT INTO clientes (nombre, apellido, email) VALUES ('"
                    + cliente.getNombre() + "', '"
                    + cliente.getApellido() + "', '"
                    + cliente.getEmail() + "')";
        insertarModificarEliminarDataBase(sql);
    }

    public List<Cliente> listarTodosLosClientes() throws Exception {
        String sql = "SELECT id, nombre, apellido FROM clientes";
        consultarDataBase(sql);
        List<Cliente> clientes = new ArrayList<>();
        while (resultSet.next()) {
            Cliente cliente = new Cliente();
            cliente.setId(resultSet.getInt("id"));
            cliente.setNombre(resultSet.getString("nombre"));
            cliente.setApellido(resultSet.getString("apellido"));
            clientes.add(cliente);
        }
        return clientes;
    }

    public void eliminarClientePorId(int id) throws Exception {
        String sql = "DELETE FROM clientes WHERE id = " + id;
        insertarModificarEliminarDataBase(sql);
    }
}

Beneficios del Patrón DAO

  1. Mantenibilidad: Permite cambios en el acceso a datos sin afectar la lógica de negocio.
  2. Flexibilidad: Facilita la migración a distintas bases de datos.
  3. Claridad: Separa claramente la lógica de negocio del acceso a datos.
  4. Reutilización: Centraliza operaciones de acceso a datos.
  5. Pruebas Unitarias: Permite probar la lógica de negocio sin depender de una base de datos real.

Uso de Clases de Servicios en Aplicaciones JDBC

Clases de Servicios

Las clases de servicios en el contexto de JDBC proporcionan una capa intermedia entre la lógica de negocio de la aplicación y las operaciones directas sobre la base de datos. Su objetivo principal es encapsular la lógica de negocio relacionada con el acceso a datos, promoviendo una mejor separación de responsabilidades y facilitando la modularidad del código.

Funcionalidades Principales de las Clases de Servicios

1. Validación y Transformación de Datos

  • Validación: Verificar la integridad y consistencia de los datos antes de persistirlos en la base de datos.
  • Transformación: Adaptar los datos recuperados de la base de datos al formato requerido por la lógica de negocio.

2. Gestión de Transacciones

  • Iniciar, confirmar y cancelar transacciones para asegurar la coherencia de las operaciones en la base de datos.
  • Garantizar la integridad de los datos mediante la coordinación adecuada de las operaciones dentro de una transacción.

3. Orquestación de Reglas de Negocio Complejas

  • Implementar y coordinar reglas de negocio que involucren múltiples operaciones de acceso a datos.
  • Asegurar que las operaciones se ejecuten correctamente siguiendo las políticas empresariales definidas.

Beneficios de Utilizar Clases de Servicios

  • Separación de Responsabilidades: Permite separar claramente la lógica de negocio de los detalles técnicos de acceso a datos, mejorando la mantenibilidad y legibilidad del código.
  • Reutilización de Código: Facilita la reutilización de métodos y funcionalidades comunes en diferentes partes de la aplicación.
  • Facilita las Pruebas Unitarias: Al encapsular la lógica de acceso a datos, se pueden crear pruebas unitarias independientes de la base de datos mediante mocks o implementaciones simuladas.

Implementación Práctica

Una clase de servicio típica podría incluir los siguientes métodos:

public class ClienteServicio {
    private ClienteDAO clienteDAO;

    public ClienteServicio() {
        this.clienteDAO = new ClienteDAO();
    }

    public Cliente buscarClientePorId(int idCliente) throws SQLException {
        return clienteDAO.buscarPorId(idCliente);
    }

    public void actualizarCliente(Cliente cliente) throws SQLException {
        validarDatosCliente(cliente);
        clienteDAO.actualizar(cliente);
    }

    private void validarDatosCliente(Cliente cliente) throws IllegalArgumentException {
        // Validaciones de negocio específicas para el cliente
        if (cliente.getNombre() == null || cliente.getNombre().isEmpty()) {
            throw new IllegalArgumentException("El nombre del cliente es requerido.");
        }
        // Otras validaciones según sea necesario
    }
}

Validaciones Adicionales en el Backend

Además de las restricciones de integridad y unicidad definidas en la base de datos, las clases de servicios JDBC pueden implementar validaciones adicionales para garantizar la consistencia de los datos. Estas validaciones son importantes por las siguientes razones:

1. Consistencia de Datos

  • Asegurar que los datos ingresados cumplen con reglas específicas del negocio.
  • Verificar, por ejemplo, que un número de identificación único no exista antes de crear un nuevo registro.

2. Mejora en la Experiencia del Usuario

  • Validar datos en el backend antes de enviarlos a la base de datos permite proporcionar mensajes de error más descriptivos y útiles.
  • Evita errores antes de la persistencia de datos, facilitando la corrección temprana de problemas.

3. Reducción de Consultas Innecesarias a la Base de Datos

  • Disminuye la cantidad de consultas evitando operaciones redundantes.
  • Ejemplo: verificar si un cliente ya existe antes de intentar insertarlo.

Note

Las clases de servicios en aplicaciones JDBC juegan un papel crucial al proporcionar una abstracción efectiva entre la lógica de negocio y el acceso a datos. Este enfoque mejora la modularidad y mantenibilidad del código, facilita la implementación de reglas de negocio complejas y optimiza la gestión de transacciones.

Clone this wiki locally