Patrón Repository con JDBC en Java

Resumen

Implementar el patrón Repository en Java te permite separar la lógica de acceso a datos del resto de tu aplicación. Aquí construyes una interfaz genérica con métodos CRUD y la aterrizas en una clase concreta llamada EmployeeRepository, usando JDBC para conectarte a la base de datos y recorrer resultados.

¿Qué métodos debe tener una interfaz Repository genérica?

La interfaz Repository se define con un tipo genérico T para que pueda reutilizarse con cualquier entidad. Esto evita repetir código cuando agregas nuevas tablas a tu proyecto.

Los métodos base que vas a declarar son cuatro y cubren las operaciones esenciales de lectura y escritura:

  • List<T> findAll() para leer todos los registros.
  • T getById(Integer id) para leer un registro específico.
  • void save(T entity) que internamente decide entre insert o update.
  • void delete(Integer id) para eliminar por identificador.

¿Por qué usar genéricos en una interfaz Repository? Porque te permite reutilizar la misma estructura para distintas entidades como Employee, Product o Customer sin reescribir las firmas de los métodos.

¿Cómo implementar findAll con JDBC y try with resources?

En EmployeeRepository cambias el genérico T por Employee al implementar la interfaz. Lo primero es declarar una conexión privada usando el patrón Singleton de tu clase DatabaseConnection:

java private Connection getConnection = DatabaseConnection.getInstance();

Dentro de findAll() usas un bloque try with resources para que el Statement y el ResultSet se cierren automáticamente. La consulta es un simple SELECT * FROM employees ejecutado con executeQuery().

¿Cómo recorrer un ResultSet y mapearlo a objetos?

Mientras myRes.next() devuelva verdadero, creas una nueva instancia de Employee y le asignas cada campo según su tipo de dato:

  • setId con myRes.getInt("id").
  • setFirstName y setSurname con getString.
  • setEmail con getString.
  • setSalary con getFloat.

Cada empleado creado se agrega a una lista declarada al inicio del método: List<Employee> employees = new ArrayList<>(). Al final, retornas esa lista.

¿Cómo refactorizar código repetido con Extract Method?

Como el mapeo de un ResultSet a un Employee se va a repetir en getById y otros métodos, conviene extraerlo. En IntelliJ seleccionas el bloque, clic derecho, Refactor y luego Extract Method. Le asignas el nombre createEmployee.

El método extraído queda así:

java private Employee createEmployee(ResultSet myRes) throws SQLException { Employee e = new Employee(); e.setId(myRes.getInt("id")); e.setFirstName(myRes.getString("firstName")); e.setSurname(myRes.getString("surname")); e.setEmail(myRes.getString("email")); e.setSalary(myRes.getFloat("salary")); return e; }

Ahora dentro del while solo necesitas llamar employees.add(createEmployee(myRes)) y tu código queda mucho más legible.

¿Qué hace Extract Method en IntelliJ? Toma un fragmento de código repetido y lo convierte en un método independiente con parámetros y retorno, mejorando la mantenibilidad sin cambiar el comportamiento.

¿Cómo implementar getById con PreparedStatement?

Para buscar un registro único usas un PreparedStatement en lugar de Statement, porque necesitas pasar parámetros de forma segura y evitar inyección SQL.

La consulta queda como SELECT * FROM employees WHERE id = ? y antes de ejecutar haces myStmt.setInt(1, id) para vincular el parámetro. Luego ejecutas executeQuery() dentro de otro try with resources anidado para el ResultSet.

Si myRes.next() devuelve verdadero, llamas a createEmployee(myRes) y asignas el resultado a la variable employee que retornarás. Si no encuentra nada, devuelve null porque la variable se inicializa en ese valor.

¿Cómo probar el repositorio desde el método main?

En tu clase Main, dentro del try que maneja la conexión, instancias el repositorio y recorres los resultados con un forEach:

java Repository<Employee> repository = new EmployeeRepository(); repository.findAll().forEach(System.out::println);

Un detalle importante que puede fallar: si al extraer createEmployee se te olvidó volver a agregar employees.add(e) dentro del bucle, la lista regresa vacía aunque la consulta funcione. Revisa siempre que el método original siga agregando el objeto a la colección.

Otro punto fácil de pasar por alto es el nombre de la tabla. En MySQL las tablas suelen ser sensibles a mayúsculas según el sistema operativo, así que verifica que employees esté escrito tal cual existe en tu base de datos.

¿Cómo mejorar la salida al imprimir empleados?

La representación por defecto de un objeto en Java muestra la clase y un hash. Para que el System.out.println muestre información legible, sobrescribe el método toString() en la clase Employee devolviendo una cadena con los campos formateados como prefieras. Comparte tu versión en los comentarios.

¿Cómo dejarías tú el toString de Employee para que la consola se vea más estilizada?