Ejecución de Store Procedures en Spring Data

Clase 24 de 25Curso de Java Spring Data JPA: Bases de Datos

Contenido del curso

Spring Data Repositories

Resumen

Cuando la lógica de negocio vive dentro de la base de datos, necesitas una forma limpia de invocarla desde tu aplicación. Spring Data JPA ofrece la anotación @Procedure, que permite declarar y ejecutar un stored procedure directamente desde un repositorio, sin escribir código JDBC manual. A través de un caso práctico —una promoción de pizza aleatoria con 20% de descuento— se muestra paso a paso cómo conectar un procedimiento almacenado con el resto de la arquitectura Spring.

¿Cómo funciona el stored procedure de la pizza aleatoria?

El procedimiento se llama take_random_pizza_order y simula una promoción: el cliente acepta recibir cualquier pizza al azar a cambio de un 20% de descuento [0:37]. Su estructura tiene tres partes fundamentales:

  • Parámetros de entrada: id_customer (identificación del cliente) y method (si es domicilio, para llevar o para consumir en el local) [1:02].
  • Parámetro de salida (out): order_taken, un booleano que indica si la orden se realizó con éxito [1:14].
  • Variables internas: el ID de la pizza seleccionada, su precio original y el precio con descuento [1:24].

Dentro del procedimiento, la selección aleatoria se logra con la función RAND() de MySQL combinada con ORDER BY y LIMIT 1. Esto devuelve exactamente una pizza disponible de forma aleatoria [1:50]. Luego se calcula el precio con descuento restando el 20% al precio original.

El bloque transaccional utiliza START TRANSACTION para insertar un registro en pizza_order y otro en order_item. Si ocurre un error se ejecuta ROLLBACK y order_taken queda en false; si todo sale bien, se hace COMMIT y retorna true [2:40].

¿Qué es LAST_INSERT_ID y por qué es importante?

La función LAST_INSERT_ID() captura el identificador autogenerado de la fila recién insertada en pizza_order [2:28]. Ese valor se reutiliza para asociar correctamente el order_item con su orden correspondiente, manteniendo la integridad referencial.

¿Cómo se declara un stored procedure en Spring Data con @Procedure?

En el OrderRepository se crea un método que refleja la firma del procedimiento [3:17]:

java @Procedure(value = "take_random_pizza_order", outputParameterName = "order_taken") boolean saveRandomOrder(@Param("id_customer") String idCustomer, @Param("method") String method);

  • La anotación @Procedure proviene de org.springframework.data.jpa.repository.query [3:55].
  • El atributo value recibe el nombre exacto del stored procedure en la base de datos.
  • outputParameterName indica el nombre del parámetro de salida, en este caso order_taken [4:15].
  • Cada parámetro de entrada se anota con @Param, y los nombres deben coincidir exactamente con los declarados en el procedimiento (id_customer, method) [4:30].

¿Cómo se conecta con el servicio y el controlador?

Se crea un DTO llamado RandomOrderDTO con la anotación @Data de Lombok, que contiene idCustomer y method [5:00]. En OrderService se expone un método que simplemente delega al repositorio:

java @Transactional public boolean saveRandomOrder(RandomOrderDTO dto) { return orderRepository.saveRandomOrder(dto.getIdCustomer(), dto.getMethod()); }

En el controlador se mapea con @PostMapping("/random") y se recibe el DTO dentro del @RequestBody, retornando un ResponseEntity<Boolean> [5:40].

¿Por qué es obligatorio usar @Transactional con @Procedure?

Al ejecutar por primera vez sin @Transactional, Spring lanza un error 500 indicando explícitamente que los métodos anotados con @Procedure requieren un contexto transaccional [6:40]. Agregar @Transactional en el método del servicio resuelve el problema de inmediato.

Una vez corregido, la petición POST a /order/random con el JSON correspondiente retorna true [7:05]. Al consultar todas las órdenes se verifica que la última incluye la nota de la promoción del 20% y la pizza asignada aleatoriamente, por ejemplo, una pizza margarita [7:25].

  • Verifica que el stored procedure exista en la base de datos antes de probar.
  • Los nombres de los parámetros en @Param deben ser idénticos a los del procedimiento.
  • Siempre anota con @Transactional el método que invoca @Procedure.

¿Has utilizado stored procedures en tus proyectos con Spring Data? Comparte tu experiencia y cuéntanos qué otros escenarios te han resultado útiles.

      Ejecución de Store Procedures en Spring Data