Contenido del curso

Spring Data Repositories

Cómo ejecutar stored procedures con @Procedure

Resumen

Ejecutar un stored procedure desde Spring Data es más simple de lo que parece: basta con la anotación @Procedure para conectar tu repositorio con la lógica que vive en la base de datos. Aquí verás cómo hacerlo paso a paso usando un caso real de una pizzería que ofrece un 20% de descuento a quien se atreva a pedir una pizza al azar.

¿Qué hace el stored procedure TakeRandomPizzaOrder?

El procedimiento almacenado encapsula toda la lógica de negocio de la promoción dentro de la base de datos, y desde Spring Data solo lo invocas. [00:30]

El TakeRandomPizzaOrder recibe dos parámetros de entrada y devuelve uno de salida:

  • id_customer: identificador del cliente que hace el pedido.
  • method: tipo de entrega (takeout, dine-in o delivery).
  • orderTaken: variable de salida tipo out que indica si la orden se procesó.

Dentro del procedimiento se declaran tres variables locales: el id de la pizza seleccionada, su precio original y el precio con descuento. La selección aleatoria se hace con ORDER BY RAND() y LIMIT 1, una función de MySQL que ordena los registros al azar y devuelve uno solo. [01:30]

¿Qué es ORDER BY RAND() en MySQL? Es una función que ordena los registros de una tabla en orden aleatorio. Combinada con LIMIT 1, te permite obtener un único registro al azar.

¿Cómo se calcula el descuento dentro del procedimiento?

El precio con descuento se obtiene restando el 20% al precio original de la pizza seleccionada. Después se abre una transacción con START TRANSACTION para insertar el registro en la tabla PizzaOrder con el id del cliente, la fecha actual, el precio rebajado, el método de pago y una nota indicando que aplica la promoción.

Luego se inserta en OrderItem usando LAST_INSERT_ID() para capturar el id del pedido recién creado. La promoción es válida para una sola pizza, así que la cantidad siempre es uno.

Si ocurre un error, la variable orderTaken se marca como false y se ejecuta un ROLLBACK. Si todo sale bien, se marca como true y se hace COMMIT. Finalmente, un SELECT orderTaken devuelve el resultado al cliente que invocó el procedimiento. [03:00]

¿Cómo declaro el stored procedure en el repositorio de Spring Data?

En OrderRepository defines un método que devuelva boolean y le aplicas la anotación @Procedure importada desde org.springframework.data.jpa.repository.Query.

java @Procedure(value = "TakeRandomPizzaOrder", outputParameterName = "orderTaken") Boolean saveRandomOrder(@Param("id_customer") String idCustomer, @Param("method") String method);

Dos detalles que importan:

  • El atributo value lleva el nombre exacto del stored procedure en la base de datos.
  • outputParameterName debe coincidir con el nombre de la variable de salida, en este caso orderTaken.
  • Los @Param deben usar los mismos nombres que los parámetros de entrada del procedimiento, como id_customer y method. [04:30]

¿Para qué sirve outputParameterName en @Procedure? Le indica a Spring Data cuál es la variable de salida del procedimiento que debe mapearse al valor de retorno del método Java.

¿Cómo conecto el service y el controller?

En OrderService creas un método saveRandomOrder que reciba un DTO. Para mantener la información ordenada, declaras una clase RandomOrderDTO con la anotación @Data y dos atributos tipo String: id_customer y method.

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

La anotación @Transactional es obligatoria cuando llamas un método con @Procedure. Sin ella, Spring lanza una excepción al intentar ejecutar el procedimiento. [07:00]

En el controller expones el endpoint:

java @PostMapping("/random") public ResponseEntity<Boolean> randomOrder(@RequestBody RandomOrderDTO dto) { return ResponseEntity.ok(this.orderService.saveRandomOrder(dto)); }

¿Por qué falla la primera ejecución y cómo lo soluciono?

Al probar el endpoint /order/random desde Postman con un JSON que incluya id_customer y method, recibes un error 500. La consola muestra un mensaje claro: para ejecutar un método anotado con @Procedure, necesitas envolverlo con @Transactional.

Esa anotación abre el contexto transaccional que el stored procedure requiere para manejar START TRANSACTION, COMMIT y ROLLBACK correctamente desde JPA. Una vez agregada al método del service, la siguiente petición devuelve un 200 con true como respuesta. [08:00]

Para confirmar el resultado, basta con hacer un GET a todos los pedidos. El último registro incluye la nota de la promoción del 20% y la pizza seleccionada al azar, en el ejemplo una Margherita para el cliente Carl Austin.

¿Ya implementaste stored procedures con Spring Data en tus proyectos? Cuéntame en los comentarios qué casos de uso le has dado.