Gymterview
middle

Criteria API — что это и когда использовать?

Criteria API — программный (type-safe) способ построения запросов в JPA. В отличие от JPQL (строковые запросы), Criteria API использует Java-объекты для построения запроса, что обеспечивает проверку на этапе компиляции.

Базовый пример

Пример
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<User> query = cb.createQuery(User.class);
Root<User> user = query.from(User.class);

// SELECT u FROM User u WHERE u.status = 'ACTIVE' AND u.name LIKE '%John%'
query.select(user)
     .where(
         cb.and(
             cb.equal(user.get("status"), UserStatus.ACTIVE),
             cb.like(user.get("name"), "%John%")
         )
     )
     .orderBy(cb.asc(user.get("name")));

List<User> result = entityManager.createQuery(query).getResultList();

Динамические запросы — основное преимущество

Пример динамического фильтра
public List<User> search(String name, UserStatus status, String email) {
    CriteriaBuilder cb = entityManager.getCriteriaBuilder();
    CriteriaQuery<User> query = cb.createQuery(User.class);
    Root<User> user = query.from(User.class);

    List<Predicate> predicates = new ArrayList<>();

    if (name != null) {
        predicates.add(cb.like(cb.lower(user.get("name")), "%" + name.toLowerCase() + "%"));
    }
    if (status != null) {
        predicates.add(cb.equal(user.get("status"), status));
    }
    if (email != null) {
        predicates.add(cb.equal(user.get("email"), email));
    }

    query.where(predicates.toArray(new Predicate[0]));
    return entityManager.createQuery(query).getResultList();
}

Spring Data JPA Specification (обёртка над Criteria API)

Пример Specification
public class UserSpecifications {
    public static Specification<User> hasName(String name) {
        return (root, query, cb) -> cb.like(cb.lower(root.get("name")), "%" + name.toLowerCase() + "%");
    }

    public static Specification<User> hasStatus(UserStatus status) {
        return (root, query, cb) -> cb.equal(root.get("status"), status);
    }
}

// Использование
public interface UserRepository extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> {}

List<User> users = userRepository.findAll(
    Specification.where(UserSpecifications.hasName("John"))
                 .and(UserSpecifications.hasStatus(UserStatus.ACTIVE))
);

Важное

  • Criteria API — type-safe построение запросов через Java-объекты
  • Основное преимущество — динамические запросы с переменным набором условий
  • Для статических запросов JPQL проще и читаемее
  • Spring Data Specification — удобная обёртка над Criteria API

Частые ошибки

  • Использовать Criteria для простых запросов — JPQL намного читаемее для статических запросов
  • Строки вместо Metamodel — user.get("name") не проверяется компилятором; опечатка обнаружится только в runtime
  • Не подключить Metamodel Generator — без User_ теряется основное преимущество type-safety

Как используется в 2026

  • Spring Data Specification — стандарт для динамических фильтров в REST API
  • QueryDSL — популярная альтернатива Criteria API с более читаемым синтаксом (но проблемы с поддержкой Jakarta)
  • Для сложных запросов — jOOQ набирает популярность как type-safe альтернатива

На собеседовании: Criteria API — для динамических запросов, JPQL — для статических. Упомяните Spring Data Specification как удобную обёртку. Если спросят про type-safety — расскажите про JPA Static Metamodel Generator (User_). QueryDSL — альтернатива с лучшим синтаксисом.