Clase Conexion - eliizquierdo/material_programacion_avanzada2026 GitHub Wiki

📦 Proyecto: mini-crud-sql (Tema 3 — JDBC + MySQL) — ⬇️ Descargar ZIP · ☁️ Abrir en Codespace

🔌 Clase Conexion

¿Por qué necesitamos esta clase?

Sin una clase Conexion, cada vez que un DAO necesita acceder a la base de datos tendría que repetir todo esto:

// ❌ Código repetitivo en CADA método del DAO
String url = "jdbc:mysql://localhost:3306/institutoWeb?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC";
Connection con = DriverManager.getConnection(url, "root", "admin123");
// ... usar la conexión
con.close();

Si la contraseña cambia, hay que buscar y cambiar en 10 lugares distintos.

Con la clase Conexion, cualquier DAO hace simplemente:

// ✅ Una sola línea
Connection con = Conexion.obtener();

Ventajas:

  • Los parámetros de conexión están en un solo lugar
  • Las credenciales van en un archivo separado, no en el código Java
  • El cierre de la conexión lo maneja try-with-resources automáticamente

¿Qué es una Factoría Estática?

La clase usa el patrón Static Factory Method: un método static que crea y devuelve objetos sin necesidad de usar new.

La palabra clave static permite llamar al método usando el nombre de la clase directamente:

Connection con = Conexion.obtener(); // sin new, sin instancia

Paso 1 — Archivo de configuración (db.properties)

Las credenciales van en un archivo de texto separado, no en el código Java. Esto es importante porque:

  • Si alguien ve tu código en GitHub, no ve la contraseña
  • Si cambia la contraseña, solo cambias el .properties, no el .java

Ubicación: src/main/resources/db.properties

# Configuración de la base de datos
db.url=jdbc:mysql://localhost:3306/institutoWeb?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC
db.username=java_dev
db.password=java2026

Anatomía de la URL JDBC

jdbc:mysql://localhost:3306/institutoWeb?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC
└────┬───┘   └──────┬─────┘ └─────┬────┘ └─────────────────────────────┬────────────────────────────┘
 Protocolo  Servidor y puerto Base de datos                  Parámetros opcionales
Parte Descripción
jdbc:mysql Protocolo para conectarse a MySQL desde Java
localhost:3306 Servidor local, puerto 3306 (el de MySQL por defecto)
/institutoWeb Nombre de la base de datos
useSSL=false Desactiva SSL en entornos de desarrollo
allowPublicKeyRetrieval=true Necesario en MySQL 8.x: sin esto, la conexión falla con "Public Key Retrieval is not allowed" al usar el método de autenticación por defecto
serverTimezone=UTC Necesario en MySQL 8.x para evitar errores de zona horaria

Paso 2 — Clase Conexion.java

package modelo.conexion;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;

/**
 * Factoría estática de conexiones a la base de datos.
 * Las credenciales se leen desde src/main/resources/db.properties.
 */
public class Conexion {

    private static final String ARCHIVO = "db.properties";

    // Registrar el driver JDBC explícitamente (evita "No suitable driver found" en Tomcat)
    static {
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            System.err.println("ERROR: No se encontró el driver de MySQL en el classpath.");
            e.printStackTrace();
        }
    }

    // Las propiedades se cargan UNA SOLA VEZ cuando arranca la aplicación
    private static final Properties config = cargarPropiedades();

    // ── Carga del archivo de propiedades ──────────────────────────────────

    private static Properties cargarPropiedades() {
        Properties props = new Properties();
        try (InputStream input = Conexion.class
                .getClassLoader()
                .getResourceAsStream(ARCHIVO)) {

            if (input == null) {
                System.err.println("ERROR: No se encontró " + ARCHIVO);
                return props;
            }
            props.load(input);

        } catch (Exception e) {
            System.err.println("ERROR al leer " + ARCHIVO);
            e.printStackTrace();
        }
        return props;
    }

    // ── Método principal: devuelve una nueva conexión ─────────────────────

    /**
     * Devuelve una nueva conexión a la base de datos.
     * Recuerda cerrarla con try-with-resources en el DAO.
     */
    public static Connection obtener() throws SQLException {
        String url      = config.getProperty("db.url");
        String usuario  = config.getProperty("db.username");
        String password = config.getProperty("db.password");
        return DriverManager.getConnection(url, usuario, password);
    }
}

🐛 Por qué el bloque static con Class.forName(...)

En teoría, desde JDBC 4.0 el DriverManager debería descubrir el driver de MySQL solo, sin necesidad de cargarlo a mano. En la práctica, dentro de Tomcat esto puede fallar con el error SQLException: No suitable driver found, aunque el .jar del driver esté correctamente en WEB-INF/lib.

Esto pasa porque Tomcat aísla el classloader de cada aplicación web, y el mecanismo automático de DriverManager a veces no llega a "ver" el driver cargado por ese classloader aislado. La solución es forzar la carga de la clase del driver con Class.forName(...) dentro de un bloque static — así se ejecuta una sola vez, apenas se carga la clase Conexion, y garantiza que el driver quede registrado antes de la primera conexión.


Paso 3 — Cómo usarla en el DAO

El DAO usa try-with-resources: Java cierra la conexión automáticamente al salir del bloque, aunque haya un error. No hace falta escribir un bloque finally.

// Ejemplo: listar todas las personas
public ArrayList<PersonaVO> getLista() {
    ArrayList<PersonaVO> lista = new ArrayList<>();
    String sql = "SELECT * FROM personas";

    try (Connection con = Conexion.obtener();
         PreparedStatement ps = con.prepareStatement(sql);
         ResultSet rs = ps.executeQuery()) {

        while (rs.next()) {
            lista.add(new PersonaVO(rs.getInt("codigo"), rs.getString("nombre")));
        }
    } catch (SQLException e) {
        e.printStackTrace();
    }
    // ← con, ps y rs se cierran solos aquí (try-with-resources)
    return lista;
}

⚠️ Limitaciones

Sin pool de conexiones: cada llamada a obtener() abre una conexión nueva y la cierra. Para aplicaciones con muchos usuarios simultáneos, esto es lento (~100ms por conexión). La solución es usar HikariCP o Apache DBCP.

Credenciales en texto plano: el .properties sigue siendo texto legible. En producción, se usan variables de entorno o servicios de secretos.


Continuamos por la clase PersonaDAO → MODELO-PersonaDAO


📋 Palabras clave

Conexion · db.properties · Static Factory Method · Conexion.obtener() · try-with-resources · URL JDBC · jdbc:mysql · DriverManager · credenciales · useSSL · serverTimezone · cargarPropiedades · no hardcodear


🧠 Autoevaluación — Clase Conexion


← Introducción: BD + Web · 🏠 Inicio · Clase PersonaDAO actualizada →

⚠️ **GitHub.com Fallback** ⚠️