Llamando procedimientos almacenados con JPA y Spring Data JPA: una guía práctica

Advertisements

Cuando trabajas con bases de datos relacionales, los procedimientos almacenados son una forma común de encapsular lógica de negocio a nivel de base de datos. En aplicaciones Java que usan JPA (Java Persistence API), llamar procedimientos almacenados ha evolucionado con los años. En este artículo veremos cómo llamar procedimientos almacenados usando versiones antiguas de JPA, las mejoras introducidas en JPA 2.1 / 2.2, y cómo aprovechar Spring Data JPA para un enfoque más declarativo.

¿Por qué usar procedimientos almacenados?

Los procedimientos almacenados son sentencias SQL precompiladas que residen en la base de datos. Ofrecen:

  • Rendimiento: menor tráfico de red y mejores planes de ejecución.
  • Seguridad: control de acceso a nivel de base de datos.
  • Reutilización: lógica compartida entre aplicaciones y sistemas.

Llamar procedimientos almacenados con versiones antiguas de JPA (antes de JPA 2.1)

Antes de JPA 2.1, llamar procedimientos almacenados era algo más verboso y menos intuitivo. Los desarrolladores normalmente dependían del método createNativeQuery del EntityManager.

Ejemplo:

Supongamos que tenemos un procedimiento almacenado en MySQL:

CREATE PROCEDURE GET_EMPLOYEE_BY_ID(IN emp_id INT)
BEGIN
    SELECT * FROM employee WHERE id = emp_id;
END;

Puedes llamar este procedimiento en JPA de la siguiente forma:

Query query = entityManager.createNativeQuery("CALL GET_EMPLOYEE_BY_ID(?)", Employee.class);
query.setParameter(1, 1001);

List<Employee> result = query.getResultList();

Este enfoque funciona, pero carece de verificación de tipos y flexibilidad.

Mejoras en JPA 2.1 y versiones posteriores

Con JPA 2.1, el soporte para procedimientos almacenados pasó a formar parte de la especificación mediante la API StoredProcedureQuery.

Usando StoredProcedureQuery

StoredProcedureQuery query = entityManager
    .createStoredProcedureQuery("GET_EMPLOYEE_BY_ID", Employee.class)
    .registerStoredProcedureParameter(1, Integer.class, ParameterMode.IN)
    .setParameter(1, 1001);

List<Employee> result = query.getResultList();

Opcional: mapeo de parámetros de salida (OUT)

Para procedimientos con parámetros de salida, puedes registrarlos y obtenerlos así:

StoredProcedureQuery query = entityManager
    .createStoredProcedureQuery("GET_EMPLOYEE_SALARY")
    .registerStoredProcedureParameter("emp_id", Integer.class, ParameterMode.IN)
    .registerStoredProcedureParameter("salary", Double.class, ParameterMode.OUT)
    .setParameter("emp_id", 1001);

Double salary = (Double) query.getOutputParameterValue("salary");
Advertisements

JPA 2.2 y 2.3 retienen en gran medida la misma API, con mejoras menores para integrarse con características de Java 8 como Optional.

Usando procedimientos almacenados con Spring Data JPA

Spring Data JPA simplifica aún más las capas de acceso a datos al permitir que definas llamadas a procedimientos almacenados mediante interfaces de repositorio.

Ejemplo de configuración

Primero, define tu procedimiento almacenado:

CREATE PROCEDURE GET_TOTAL_EMPLOYEES(OUT total INT)
BEGIN
    SELECT COUNT(*) INTO total FROM employee;
END;

Luego, declara un método en tu repositorio y usa la anotación @Procedure, indicando el atributo que coincide con el nombre del procedimiento almacenado:

public interface EmployeeRepository extends JpaRepository<Employee, Long> {

    @Procedure(name = "getTotalEmployees")
    Integer getTotalEmployees();
}

Si tu procedimiento está asociado con una entidad, anótalo:

@Entity
@NamedStoredProcedureQuery(
    name = "getTotalEmployees",
    procedureName = "GET_TOTAL_EMPLOYEES",
    parameters = {
        @StoredProcedureParameter(mode = ParameterMode.OUT, name = "total", type = Integer.class)
    }
)
public class Employee {
    @Id
    private Long id;
    private String name;
}

Bonus: parámetros IN / OUT

Puedes usar @Procedure con argumentos de entrada/salida:

@Procedure(procedureName = "GET_EMPLOYEE_SALARY")
Double getEmployeeSalary(@Param("emp_id") Integer empId);

Spring se encarga del enlace de parámetros detrás de escena, haciendo que tu código sea más limpio y declarativo.

Resumen

EnfoqueProsContras
JPA antiguo (SQL nativo)Simple, funciona en todos ladosNo es seguro con tipos, verboso
JPA 2.1+ APISeguro con tipos, estructuradoUn poco más de código repetitivo
Spring Data JPA (declarativo)Limpio, reutilizableFlexibilidad limitada para procedimientos complejos

Conclusión

Los procedimientos almacenados siguen siendo una herramienta valiosa en aplicaciones empresariales. Ya sea que estés atascado con una versión antigua de JPA o uses la pila moderna de Spring, tienes varias maneras de integrarlos de forma limpia y efectiva. Siempre equilibra legibilidad, reutilización y control al elegir tu enfoque.

Advertisements

Leave a Reply

Your email address will not be published. Required fields are marked *