Contenido del curso
Primeros pasos
Spring Data Repositories
- 7

Qué son los Spring Data Repositories
08:39 min - 8

Guardar y Actualizar Registros con Spring Data Repositories
08:34 min - 9

Eliminar elementos con Spring Data JPA: método deleteById
05:36 min - 10

Lazy vs Eager en relaciones JPA
15:09 min - 11

Query Methods en Spring para Consultas Personalizadas
08:27 min - 12

Filtrar pizzas con Containing y Not en JPA
07:27 min - 13

Fechas y listas en query methods de JPA
11:25 min - 14

findTop y Optional en Spring Data JPA
09:30 min - 15

Paginación y Ordenación con Spring Data Repositories
07:39 min - 16

Ordenamiento Dinámico con Paging and Sorting Repository
07:58 min
Personalización de queries
Características avanzadas
Próximos pasos
Consultas con JPQL en Spring Data JPA
Resumen
Cuando trabajas con Spring Data JPA, llega un momento en que los query methods se quedan cortos y necesitas escribir consultas más expresivas sin renunciar a la orientación a objetos. Ahí entra JPQL, el lenguaje que te permite consultar la base de datos pensando en entities y atributos, no en tablas y columnas.
¿Qué es JPQL y en qué se diferencia de SQL?
JPQL, Java Persistence Query Language, es un lenguaje de consulta orientado a objetos que opera sobre las clases entity de tu aplicación. En lugar de escribir from customer apuntando a una tabla, escribes from CustomerEntity apuntando a la clase mapeada.
¿Qué es JPQL? Es un lenguaje de consultas de Java Persistence que usa entities y sus atributos en vez de tablas y columnas. Spring lo traduce a SQL nativo en tiempo de ejecución.
La sintaxis se siente familiar si vienes de SQL: select, from, where. La diferencia está en que cada referencia apunta a una clase Java y a sus campos, lo que mantiene tu código alineado con el modelo de dominio.
¿Cómo crear un repositorio con @Query en JPQL?
El primer paso es definir una interfaz que extienda de ListCrudRepository, indicando el entity y el tipo de la clave primaria. En el ejemplo, CustomerEntity usa un String como identificador [01:00].
Dentro del repositorio se declara el método findByPhone, que recibe un phone y retorna un CustomerEntity. Aquí ya no se usan query methods basados en el nombre, sino la anotación @Query para escribir la consulta a mano:
java @Query("select c from CustomerEntity c where c.phoneNumber = :phone") CustomerEntity findByPhone(@Param("phone") String phone);
Fíjate en tres detalles que conviene revisar:
- El alias
crepresenta al entityCustomerEntitydentro de la consulta. c.phoneNumberreferencia el atributo de la clase, no la columna de la tabla.- Los dos puntos en
:phonedeclaran un parámetro nombrado que luego se enlaza con @Param("phone").
La anotación @Param proviene de org.springframework.data.repository.query y sirve para que la consulta sepa exactamente qué argumento del método inyectar. Aunque el parámetro Java se llame igual, conviene declararlo siempre [01:55].
¿Cómo conectar el repositorio con un servicio?
El siguiente paso es crear CustomerService y anotarlo con @Service para que Spring lo registre como bean y pueda inyectar el repositorio. Si olvidas esa anotación, verás un error en el @Autowired aunque el constructor esté bien escrito [02:30].
El servicio expone un método findByPhone(String phone) que delega directamente en customerRepository.findByPhone(phone). Esa delegación deja el servicio limpio y mantiene la lógica de acceso a datos donde corresponde.
¿Cómo exponer la consulta con un controlador REST?
El controlador se anota con @Controller y @RequestMapping("/api/customers"), e inyecta el servicio por constructor. El uso explícito de @Autowired es opcional, pero ayuda a hacer visible que la dependencia la resuelve Spring.
El endpoint queda así:
@GetMapping("/phone/{phone}")define la ruta.@PathVariable String phonecaptura el valor de la URL.- El método retorna
ResponseEntity.ok(customerService.findByPhone(phone)).
¿Para qué sirve @PathVariable? Para extraer un valor que viaja como parte de la URL y pasarlo como argumento al método del controlador. Es la forma estándar de leer rutas dinámicas como
/phone/{phone}.
Al ejecutar la aplicación y llamar /api/customers/phone/{numero} con un teléfono existente en la base pizzeria.customer, la respuesta llega con un 200 y el detalle del cliente: nombre, dirección, email, identificación y teléfono [03:45].
¿Cómo se traduce la consulta JPQL a SQL?
En la consola se ve la traducción que hace el motor: parte del JPQL escrito en el repositorio y genera un SQL nativo cuyo where filtra por phone_number. Esa equivalencia es la clave para entender por qué JPQL se siente cercano a SQL pero se escribe en términos del dominio.
La estructura se parece tanto que migrar mentalmente entre ambos cuesta poco. Aun así, hay un límite real: JPQL no soporta todas las características avanzadas del SQL nativo, como funciones específicas del motor, hints o sintaxis propietaria. Cuando necesitas eso, toca recurrir a @Query con nativeQuery = true.
¿Cuándo conviene usar JPQL frente a SQL nativo?
JPQL brilla cuando quieres mantener tu código portable entre motores de base de datos y trabajar con el modelo de objetos. SQL nativo gana cuando necesitas exprimir capacidades específicas del motor.
Una guía rápida para decidir:
- Usa JPQL si la consulta se puede expresar con entities, joins básicos y filtros estándar.
- Usa SQL nativo si necesitas funciones propias del motor, vistas materializadas o sintaxis no portable.
- Usa query methods derivados del nombre cuando la consulta sea trivial y no quieras escribir nada.
¿Qué tipo de consultas estás resolviendo hoy con JPQL en tus proyectos? Cuéntame en los comentarios cómo decides entre query methods, JPQL y SQL nativo.