CRUD completo con JDBC
Patrón Repository para acceso a datos
La clase repositorio
El patrón Repository encapsula toda la lógica de acceso a datos de una entidad en una clase dedicada. El resto de la aplicación llama a métodos del repositorio sin conocer los detalles de JDBC — del mismo modo que funcionan Spring Data JPA o Hibernate, pero sin el framework.
import java.sql.*;
import java.util.*;
// Patrón Repository: encapsula todo el acceso a datos de una entidad
public class ClienteRepositorio {
private final DataSource dataSource;
public ClienteRepositorio(DataSource dataSource) {
this.dataSource = dataSource;
}
// CREATE
public long insertar(Cliente c) throws SQLException {
String sql = "INSERT INTO clientes (nombre, email, activo) VALUES (?, ?, ?)";
try (Connection con = dataSource.getConnection();
PreparedStatement ps = con.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
ps.setString(1, c.getNombre());
ps.setString(2, c.getEmail());
ps.setBoolean(3, c.isActivo());
ps.executeUpdate();
try (ResultSet keys = ps.getGeneratedKeys()) {
keys.next();
return keys.getLong(1);
}
}
} // READ por ID
public Optional<Cliente> buscarPorId(long id) throws SQLException {
String sql = "SELECT id, nombre, email, activo FROM clientes WHERE id = ?";
try (Connection con = dataSource.getConnection();
PreparedStatement ps = con.prepareStatement(sql)) {
ps.setLong(1, id);
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) return Optional.of(mapear(rs));
return Optional.empty();
}
}
}
// READ lista
public List<Cliente> buscarTodos() throws SQLException {
String sql = "SELECT id, nombre, email, activo FROM clientes ORDER BY nombre";
List<Cliente> lista = new ArrayList<>();
try (Connection con = dataSource.getConnection();
PreparedStatement ps = con.prepareStatement(sql);
ResultSet rs = ps.executeQuery()) {
while (rs.next()) lista.add(mapear(rs));
}
return lista;
}
// UPDATE
public int actualizar(Cliente c) throws SQLException {
String sql = "UPDATE clientes SET nombre = ?, email = ?, activo = ? WHERE id = ?";
try (Connection con = dataSource.getConnection();
PreparedStatement ps = con.prepareStatement(sql)) {
ps.setString(1, c.getNombre());
ps.setString(2, c.getEmail());
ps.setBoolean(3, c.isActivo());
ps.setLong(4, c.getId());
return ps.executeUpdate(); // filas afectadas
}
}
// DELETE
public int eliminar(long id) throws SQLException {
String sql = "DELETE FROM clientes WHERE id = ?";
try (Connection con = dataSource.getConnection();
PreparedStatement ps = con.prepareStatement(sql)) {
ps.setLong(1, id);
return ps.executeUpdate();
}
}
private Cliente mapear(ResultSet rs) throws SQLException {
Cliente c = new Cliente();
c.setId(rs.getLong("id"));
c.setNombre(rs.getString("nombre"));
c.setEmail(rs.getString("email"));
c.setActivo(rs.getBoolean("activo"));
return c;
}
} Uso del repositorio
// Uso del repositorio
DataSource ds = crearDataSource(); // HikariCP, DriverManager, etc.
ClienteRepositorio repo = new ClienteRepositorio(ds);
// Crear
Cliente nuevo = new Cliente();
nuevo.setNombre("Ana García");
nuevo.setEmail("ana@ejemplo.com");
nuevo.setActivo(true);
long id = repo.insertar(nuevo);
System.out.println("Creado con id: " + id);
// Leer
Optional<Cliente> encontrado = repo.buscarPorId(id);
encontrado.ifPresent(c -> System.out.println("Encontrado: " + c.getNombre()));
// Actualizar
encontrado.ifPresent(c -> {
c.setEmail("nuevo@ejemplo.com");
try { repo.actualizar(c); } catch (SQLException e) { throw new RuntimeException(e); }
});
// Eliminar
int filas = repo.eliminar(id);
System.out.println("Eliminados: " + filas + " registros");