← Назад к вопросам

Какие языки понимает Hibernate

2.3 Middle🔥 121 комментариев
#ORM и Hibernate

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Языки запросов в Hibernate

Hibernate — это ORM фреймворк, поддерживающий несколько языков запросов для работы с базами данных. Рассмотрю основные языки и их использование.

1. HQL (Hibernate Query Language)

HQL — это объектно-ориентированный язык запросов, специфичный для Hibernate. Синтаксис похож на SQL, но работает с сущностями (entities), а не с таблицами.

// Синтаксис HQL
public List<User> getAllUsers() {
    String hql = "FROM User WHERE active = true";
    Query query = session.createQuery(hql);
    return query.getResultList();
}

// С параметрами
public User getUserByEmail(String email) {
    String hql = "FROM User WHERE email = :email";
    Query query = session.createQuery(hql);
    query.setParameter("email", email);
    return (User) query.getSingleResult();
}

// JOIN
public List<User> getUsersWithDepartments() {
    String hql = "SELECT u FROM User u JOIN u.department d WHERE d.name = :deptName";
    Query query = session.createQuery(hql);
    query.setParameter("deptName", "Engineering");
    return query.getResultList();
}

// Агрегация
public Long countActiveUsers() {
    String hql = "SELECT COUNT(u) FROM User u WHERE u.active = true";
    Query query = session.createQuery(hql);
    return (Long) query.getSingleResult();
}

// GROUP BY
public List<Object[]> getUserCountByDepartment() {
    String hql = "SELECT d.name, COUNT(u) FROM User u JOIN u.department d GROUP BY d.name";
    Query query = session.createQuery(hql);
    return query.getResultList();
}

Плюсы HQL:

  • Независим от БД (работает с PostgreSQL, MySQL, Oracle, т.д.)
  • Понятен разработчикам, знающим SQL
  • Работает с Hibernate relationships

Минусы HQL:

  • Не стандартизирован (специфичен для Hibernate)
  • Может быть медленнее, чем native SQL
  • Требует знания Hibernate API

2. JPQL (Java Persistence Query Language)

JPQL — это стандартизированный язык запросов, определённый в JPA спецификации. Похож на HQL, но более портативен.

// Использование с Spring Data JPA и EntityManager
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    
    @Query("SELECT u FROM User u WHERE u.email = :email")
    Optional<User> findByEmail(@Param("email") String email);
    
    @Query("SELECT u FROM User u JOIN u.department d WHERE d.name = :deptName")
    List<User> findByDepartmentName(@Param("deptName") String deptName);
    
    @Query("SELECT COUNT(u) FROM User u WHERE u.active = true")
    Long countActiveUsers();
}

// В сервисе
@Service
public class UserService {
    
    @Autowired
    private EntityManager entityManager;
    
    public List<User> getUsersWithJpql() {
        String jpql = "SELECT u FROM User u WHERE u.salary > :minSalary";
        TypedQuery<User> query = entityManager.createQuery(jpql, User.class);
        query.setParameter("minSalary", 50000);
        return query.getResultList();
    }
}

Плюсы JPQL:

  • Стандартизирован (работает с любой JPA реализацией)
  • Портативен между ORM фреймворками
  • Встроен в Spring Data JPA

Минусы JPQL:

  • Меньше возможностей, чем HQL
  • Может быть медленнее, чем native SQL

3. Criteria API

Criteria API — это программный подход к построению запросов. Запрос строится с помощью Java объектов вместо строк.

public List<User> getUsersByCriteria(String departmentName, int minSalary) {
    CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
    CriteriaQuery<User> criteriaQuery = criteriaBuilder.createQuery(User.class);
    
    Root<User> userRoot = criteriaQuery.from(User.class);
    Join<User, Department> departmentJoin = userRoot.join("department");
    
    Predicate departmentPredicate = criteriaBuilder.equal(
        departmentJoin.get("name"), departmentName
    );
    Predicate salaryPredicate = criteriaBuilder.greaterThan(
        userRoot.get("salary"), minSalary
    );
    
    criteriaQuery.where(
        criteriaBuilder.and(departmentPredicate, salaryPredicate)
    );
    
    TypedQuery<User> query = entityManager.createQuery(criteriaQuery);
    return query.getResultList();
}

// Также можно использовать QueryDSL (более удобнее)
import com.querydsl.jpa.impl.JPAQueryFactory;

public List<User> getUsersByQueryDSL(String departmentName, int minSalary) {
    JPAQueryFactory queryFactory = new JPAQueryFactory(entityManager);
    
    List<User> users = queryFactory
        .selectFrom(QUser.user)
        .join(QUser.user.department, QDepartment.department)
        .where(
            QDepartment.department.name.eq(departmentName),
            QUser.user.salary.gt(minSalary)
        )
        .fetch();
    
    return users;
}

Плюсы Criteria API:

  • Type-safe (ошибки видны при компиляции, не в runtime)
  • Динамические запросы (легко добавлять условия)
  • IDE автодополнение

Минусы Criteria API:

  • Verbose (много кода)
  • Медленнее HQL/JPQL
  • Сложнее для начинающих

QueryDSL лучше:

  • Более читаемый синтаксис
  • Лучше поддержка IDE
  • Active community

4. Native SQL

Native SQL — это чистый SQL запрос к БД. Используется для сложных операций, которые сложно выразить в HQL/JPQL.

public List<User> getUsersByNativeSQL() {
    String sql = "SELECT * FROM users WHERE active = true AND salary > ?1";
    Query query = session.createNativeQuery(sql, User.class);
    query.setParameter(1, 50000);
    return query.getResultList();
}

// С параметрами
public List<User> getUsersByNativeSQLWithParams(int minSalary) {
    String sql = "SELECT u.id, u.name, u.email, u.salary FROM users u " +
                 "WHERE u.salary > :minSalary AND u.department_id IN (" +
                 "  SELECT d.id FROM departments d WHERE d.active = true" +
                 ")";
    
    Query query = session.createNativeQuery(sql);
    query.setParameter("minSalary", minSalary);
    
    List<Object[]> results = query.getResultList();
    return results.stream()
        .map(row -> new User(
            (Long) row[0],
            (String) row[1],
            (String) row[2],
            (BigDecimal) row[3]
        ))
        .collect(Collectors.toList());
}

// Можно скамапить на entity
public List<User> getUsersNativeWithMapping() {
    String sql = "SELECT * FROM users WHERE active = true";
    Query query = session.createNativeQuery(sql, User.class);
    return query.getResultList();
}

Плюсы Native SQL:

  • Полная мощь SQL
  • Легко оптимизировать
  • Поддержка уникальных функций БД (PostgreSQL JSON, Oracle CONNECT BY, т.д.)

Минусы Native SQL:

  • Зависит от конкретной БД
  • Сложнее поддерживать (синтаксис разных БД отличается)
  • Не использует lazy loading, relationships Hibernate
  • SQL injection риск (нужно использовать параметры)

5. NamedQueries

NamedQueries — это предопределённые запросы, определённые как аннотации в сущности.

@Entity
@Table(name = "users")
@NamedQueries({
    @NamedQuery(
        name = "User.findByEmail",
        query = "SELECT u FROM User u WHERE u.email = :email"
    ),
    @NamedQuery(
        name = "User.findActiveUsers",
        query = "SELECT u FROM User u WHERE u.active = true"
    ),
    @NamedQuery(
        name = "User.findByDepartment",
        query = "SELECT u FROM User u JOIN u.department d WHERE d.name = :deptName"
    )
})
public class User {
    @Id
    private Long id;
    
    @Column(name = "email")
    private String email;
    
    @Column(name = "active")
    private boolean active;
    
    @ManyToOne
    @JoinColumn(name = "department_id")
    private Department department;
}

// Использование
public User findUserByEmail(String email) {
    Query query = session.getNamedQuery("User.findByEmail");
    query.setParameter("email", email);
    return (User) query.getSingleResult();
}

Плюсы NamedQueries:

  • Централизованное управление запросами
  • Предварительная валидация
  • Переиспользование

Минусы NamedQueries:

  • Сложнее динамические запросы
  • Отделены от кода, где используются

6. Spring Data Repository Query Methods

Spring Data предоставляет простой способ создания запросов из имён методов.

public interface UserRepository extends JpaRepository<User, Long> {
    
    // Query method (Spring Data автоматически генерирует query)
    User findByEmail(String email);
    
    List<User> findByActive(boolean active);
    
    List<User> findByDepartmentName(String departmentName);
    
    List<User> findBySalaryGreaterThan(BigDecimal salary);
    
    List<User> findByEmailContaining(String emailPart);
    
    // С сортировкой
    List<User> findByActiveTrueOrderBySalaryDesc();
    
    // С пагинацией
    Page<User> findByActive(boolean active, Pageable pageable);
}

// Использование
@Service
public class UserService {
    
    @Autowired
    private UserRepository userRepository;
    
    public User getUserByEmail(String email) {
        return userRepository.findByEmail(email);
    }
    
    public List<User> getActiveUsers(Sort sort) {
        return userRepository.findByActive(true, sort);
    }
}

Плюсы:

  • Минимум кода
  • Читаемо
  • Не требует писать SQL/HQL

Минусы:

  • Ограничены простыми запросами
  • Для сложных нужны @Query

7. Comparison таблица

ЯзыкНезависим от БДType-safeSimplePerformanceГибкость
HQLGoodHigh
JPQLGoodMedium
Criteria APIMediumHigh
Native SQLExcellentVery High
QueryDSLGoodVery High
Query MethodsGoodLow

Когда использовать

// Простой запрос по одному полю → Query Method
User user = userRepository.findByEmail(email);

// Средняя сложность с несколькими условиями → JPQL с @Query
@Query("SELECT u FROM User u WHERE u.email = :email AND u.active = true")
User findByEmailAndActive(@Param("email") String email);

// Динамические условия → Criteria API или QueryDSL
List<User> users = getUsersWithCriteria(departmentName, minSalary);

// Очень сложный запрос, специфичный для БД → Native SQL
String sql = "SELECT * FROM users u " +
            "WHERE u.salary > (SELECT AVG(salary) FROM users)";
Query query = session.createNativeQuery(sql, User.class);

// Нужна type-safety и красивый синтаксис → QueryDSL
List<User> users = queryFactory
    .selectFrom(QUser.user)
    .where(QUser.user.salary.gt(50000))
    .orderBy(QUser.user.salary.desc())
    .fetch();

Выводы

Hibernate поддерживает:

  1. HQL — объектно-ориентированный язык (специфичный для Hibernate)
  2. JPQL — стандартизированный язык (JPA)
  3. Criteria API — программный подход (type-safe)
  4. Native SQL — чистый SQL (максимальная гибкость)
  5. QueryDSL — type-safe DSL (лучший выбор для сложных запросов)
  6. Spring Data Query Methods — из имён методов (для простых запросов)

Рекомендация: Используй Spring Data Query Methods для простого, JPQL с @Query для среднего, QueryDSL для сложного, Native SQL для очень специфичного.