Ответ
JPA предоставляет несколько механизмов для определения запросов, выходящих за рамки стандартных CRUD-операций.
1. Query Methods в Spring Data JPA (Наиболее простой)
Spring Data JPA может автоматически генерировать запросы на основе имени метода в репозитории.
public interface UserRepository extends JpaRepository<User, Long> {
// SELECT * FROM user WHERE email = ?
List<User> findByEmail(String email);
// SELECT * FROM user WHERE name LIKE ? AND age > ?
List<User> findByNameContainingAndAgeGreaterThan(String namePart, int age);
}
2. Аннотация @Query (JPQL или Native SQL)
Позволяет явно указать запрос на JPQL или нативном SQL.
public interface UserRepository extends JpaRepository<User, Long> {
// JPQL запрос (работает с сущностями)
@Query("SELECT u FROM User u WHERE u.active = true AND u.role = :role")
List<User> findActiveUsersByRole(@Param("role") UserRole role);
// Нативный SQL запрос (работает с таблицами)
@Query(value = "SELECT * FROM users u WHERE u.registration_date > :date",
nativeQuery = true)
List<User> findUsersRegisteredAfter(@Param("date") LocalDate date);
}
3. Именованные запросы (@NamedQuery / @NamedNativeQuery)
Запросы определяются статически в аннотациях к классу сущности, а затем вызываются по имени.
@Entity
@NamedQuery(
name = "User.findByStatus",
query = "SELECT u FROM User u WHERE u.status = :status"
)
public class User { ... }
// В репозитории или EntityManager
List<User> users = entityManager.createNamedQuery("User.findByStatus", User.class)
.setParameter("status", "ACTIVE")
.getResultList();
4. Criteria API (Типобезопасный программный API)
Используется для динамического построения сложных запросов в runtime.
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<User> query = cb.createQuery(User.class);
Root<User> user = query.from(User.class);
// Построение предикатов
Predicate namePredicate = cb.like(user.get("name"), "%John%");
Predicate agePredicate = cb.gt(user.get("age"), 21);
query.select(user).where(cb.and(namePredicate, agePredicate));
List<User> result = entityManager.createQuery(query).getResultList();
5. Использование EntityManager для JPQL/Criteria/Native Query
Низкоуровневый доступ для прямого выполнения запросов.
// JPQL
TypedQuery<User> jpqlQuery = entityManager.createQuery(
"SELECT u FROM User u JOIN u.orders o WHERE o.total > :minTotal", User.class
).setParameter("minTotal", 100.0);
// Нативный SQL
Query nativeQuery = entityManager.createNativeQuery(
"SELECT u.* FROM users u WHERE u.id IN (:ids)", User.class
).setParameter("ids", idList);
Рекомендации по выбору:
- Для простых запросов — Query Methods.
- Для сложных, но статических запросов —
@Queryс JPQL. - Для максимальной производительности или использования специфичных функций СУБД —
@Queryс nativeQuery=true (осторожно, теряется переносимость). - Для динамических запросов с переменным набором условий — Criteria API или QueryDSL.
- Всегда используйте параметризованные запросы (
:paramили?) для предотвращения SQL-инъекций.