Acceso a bases de datos con JDBC: tutorial completo Java 21

JDBC ofrece tres formas de ejecutar SQL. La elección correcta es fundamental para la seguridad y el rendimiento.

Statement: solo para SQL sin parámetros

try (Connection con = DatabaseConfig.getConnection();
     Statement  st  = con.createStatement()) {

    // DDL
    st.execute("CREATE TABLE IF NOT EXISTS productos (id INT PRIMARY KEY AUTO_INCREMENT, nombre VARCHAR(100))");

    // Consulta estática (sin parámetros de usuario)
    ResultSet rs = st.executeQuery("SELECT COUNT(*) FROM productos");
    if (rs.next()) System.out.println("Total: " + rs.getInt(1));

    // Actualización
    int afectadas = st.executeUpdate("UPDATE productos SET activo=1 WHERE stock > 0");
}

PreparedStatement: la opción correcta para parámetros

PreparedStatement protege contra SQL Injection y mejora el rendimiento porque la base de datos puede compilar y cachear el plan de ejecución:

String sql = "INSERT INTO productos (nombre, precio, categoria) VALUES (?, ?, ?)";

try (Connection con = DatabaseConfig.getConnection();
     PreparedStatement ps = con.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {

    ps.setString(1, "Teclado mecánico");
    ps.setDouble(2, 89.99);
    ps.setString(3, "Periféricos");
    ps.executeUpdate();

    // Obtener el ID generado
    try (ResultSet keys = ps.getGeneratedKeys()) {
        if (keys.next()) System.out.println("ID insertado: " + keys.getLong(1));
    }
}

Leer resultados con ResultSet

String sql = "SELECT id, nombre, precio, fecha_alta FROM productos WHERE categoria=? AND precio BETWEEN ? AND ?";

try (Connection con = DatabaseConfig.getConnection();
     PreparedStatement ps = con.prepareStatement(sql)) {

    ps.setString(1, "Periféricos");
    ps.setDouble(2, 20.0);
    ps.setDouble(3, 200.0);

    try (ResultSet rs = ps.executeQuery()) {
        while (rs.next()) {
            int    id      = rs.getInt("id");
            String nombre  = rs.getString("nombre");
            double precio  = rs.getDouble("precio");
            LocalDate alta = rs.getObject("fecha_alta", LocalDate.class); // java.time directo en JDBC 4.2+

            System.out.printf("  %d %-30s %.2f€  alta:%s%n", id, nombre, precio, alta);
        }
    }
}

Mapear ResultSet a registros Java 21

record Producto(int id, String nombre, double precio, LocalDate fechaAlta) {}

List<Producto> listar(String categoria) throws SQLException {
    String sql = "SELECT id, nombre, precio, fecha_alta FROM productos WHERE categoria=? ORDER BY nombre";
    List<Producto> lista = new ArrayList<>();

    try (Connection con = DatabaseConfig.getConnection();
         PreparedStatement ps = con.prepareStatement(sql)) {

        ps.setString(1, categoria);
        try (ResultSet rs = ps.executeQuery()) {
            while (rs.next()) {
                lista.add(new Producto(
                    rs.getInt("id"),
                    rs.getString("nombre"),
                    rs.getDouble("precio"),
                    rs.getObject("fecha_alta", LocalDate.class)
                ));
            }
        }
    }
    return lista;
}

CallableStatement: procedimientos almacenados

// Llamar a: CALL calcular_descuento(?, ?, ?)
try (Connection con = DatabaseConfig.getConnection();
     CallableStatement cs = con.prepareCall("{CALL calcular_descuento(?, ?, ?)}")) {

    cs.setInt(1, 42);         // parámetro IN: id_producto
    cs.setDouble(2, 0.15);    // parámetro IN: porcentaje
    cs.registerOutParameter(3, Types.DOUBLE); // parámetro OUT: precio_final
    cs.execute();
    double precioFinal = cs.getDouble(3);
    System.out.println("Precio con descuento: " + precioFinal);
}

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP
ARTÍCULO ANTERIOR