Hibernate Named Query

Hibernate Named Query

1. обзор

Основным недостатком HQL и SQL, разбросанных по объектам доступа к данным, является то, что это делает код нечитаемым. Следовательно, может иметь смысл сгруппировать все HQL и SQL в одном месте и использовать только их ссылки в реальном коде доступа к данным. К счастью, Hibernate позволяет нам делать это с именованными запросами.

Именованный запрос - это статически определенный запрос с предопределенной неизменяемой строкой запроса. Они проверяются при создании фабрики сеансов, что заставляет приложение быстро выходить из строя в случае ошибки.

В этой статье мы увидим, как определять и использовать именованные запросы Hibernate с помощью аннотаций@NamedQuery и@NamedNativeQuery.

2. Организация

Давайте сначала посмотрим на сущность, которую мы будем использовать в этой статье:

@Entity
public class DeptEmployee {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private long id;

    private String employeeNumber;

    private String designation;

    private String name;

    @ManyToOne
    private Department department;

    // getters and setters
}

В нашем примере мы извлекаем сотрудника по его номеру.

3. Именованный запрос

Чтобы определить это как именованный запрос, мы будем использовать аннотациюorg.hibernate.annotations.NamedQuery. Он расширяет javax.persistence.NamedQuery функциями Hibernate.

Мы определим это как аннотацию классаDeptEmployee:

@org.hibernate.annotations.NamedQuery(name = "DeptEmployee_findByEmployeeNumber",
  query = "from DeptEmployee where employeeNumber = :employeeNo")

It’s important to note that every @NamedQuery annotation is attached to exactly one entity class or mapped superclass. But,since the scope of named queries is the entire persistence unit, we should select the query name carefully to avoid a collision. И мы достигли этого, используя имя объекта в качестве префикса.

Если у нас есть более одного именованного запроса для объекта, мы будем использовать аннотацию@NamedQueries для их группировки:

@org.hibernate.annotations.NamedQueries({
    @org.hibernate.annotations.NamedQuery(name = "DeptEmployee_FindByEmployeeNumber",
      query = "from DeptEmployee where employeeNumber = :employeeNo"),
    @org.hibernate.annotations.NamedQuery(name = "DeptEmployee_FindAllByDesgination",
      query = "from DeptEmployee where designation = :designation"),
    @org.hibernate.annotations.NamedQuery(name = "DeptEmployee_UpdateEmployeeDepartment",
      query = "Update DeptEmployee set department = :newDepartment where employeeNumber = :employeeNo"),
...
})

Обратите внимание, что запрос HQL может быть операцией в стиле DML. Таким образом, это не обязательно должен быть только операторselect. Например, у нас может быть запрос на обновление, как вDeptEmployee_UpdateEmployeeDesignation выше.

3.1. Настройка функций запроса

Мы можем установить различные функции запроса с помощью саннотации@NamedQuery . Давайте посмотрим на пример:

@org.hibernate.annotations.NamedQuery(
  name = "DeptEmployee_FindAllByDepartment",
  query = "from DeptEmployee where department = :department",
  timeout = 1,
  fetchSize = 10
)

Здесь мы настроили интервал времени ожидания и размер выборки. Помимо этих двух, мы также можем установить такие функции, как:

  • cacheable - кэшируемый запрос (результаты) или нет

  • cacheMode - режим кеширования, используемый для этого запроса; это может быть один изGET, IGNORE, NORMAL, PUT, илиREFRESH

  • cacheRegion - если результаты запроса кешируемы, назовите область кэша запроса для использования

  • comment - комментарий к сгенерированному SQL-запросу; предназначен для администраторов баз данных

  • flushMode - режим очистки для этого запроса, один изALWAYS, AUTO, COMMIT, MANUAL, илиPERSISTENCE_CONTEXT

3.2. Использование именованного запроса

Теперь, когда мы определили именованный запрос, давайте воспользуемся им для получения сотрудника:

Query query = session.createNamedQuery("DeptEmployee_FindByEmployeeNumber",
  DeptEmployee.class);
query.setParameter("employeeNo", "001");
DeptEmployee result = query.getSingleResult();

Здесь мы использовали методcreateNamedQuery. Он принимает имя запроса и возвращает объект sobjectorg.hibernate.query.Query .

4. Именованный собственный запрос

Как и HQL-запросы, мы также можем определить собственный SQL как именованный запрос. Для этого мы можем использовать аннотацию@NamedNativeQuery. Хотя он похож на@NamedQuery, но требует дополнительной настройки.

Давайте рассмотрим эту аннотацию на примере:

@org.hibernate.annotations.NamedNativeQueries(
    @org.hibernate.annotations.NamedNativeQuery(name = "DeptEmployee_GetEmployeeByName",
      query = "select * from deptemployee emp where name=:name",
      resultClass = DeptEmployee.class)
)

Поскольку это собственный запрос, нам нужно указать Hibernate, с каким классом сущности сопоставлять результаты. Следовательно, мы использовали для этого свойствоresultClass .

Другой способ сопоставить результаты - использовать свойствоresultSetMapping . Здесь мы можем указать имя предварительно определенногоSQLResultSetMapping.

Обратите внимание, что мы можем использовать только один изresultClass иresultSetMapping.

4.1. Использование именованного собственного запроса

Чтобы использовать именованный собственный запрос, мы можем использоватьSession.createNamedQuery():

Query query = session.createNamedQuery("DeptEmployee_FindByEmployeeName", DeptEmployee.class);
query.setParameter("name", "John Wayne");
DeptEmployee result = query.getSingleResult();

ИлиSession.getNamedNativeQuery():

NativeQuery query = session.getNamedNativeQuery("DeptEmployee_FindByEmployeeName");
query.setParameter("name", "John Wayne");
DeptEmployee result = (DeptEmployee) query.getSingleResult();

Единственная разница между этими двумя подходами - это тип возвращаемого значения. Второй подход возвращаетNativeQuery, w, который является подклассомQuery.

5. Хранимые процедуры и функции

Мы можем использовать аннотацию@NamedNativeQuery для определения вызовов хранимых процедур и функций:

@org.hibernate.annotations.NamedNativeQuery(
  name = "DeptEmployee_UpdateEmployeeDesignation",
  query = "call UPDATE_EMPLOYEE_DESIGNATION(:employeeNumber, :newDesignation)",
  resultClass = DeptEmployee.class)

Обратите внимание, что хотя это запрос на обновление, мы использовали свойствоresultClass . Это связано с тем, что Hibernate не поддерживает чистые нативные скалярные запросы. И способ обойти проблему - установитьresultClass илиresultSetMapping.

6. Заключение

В этой статье мы увидели, как определять и использовать именованные HQL и собственные запросы.

Исходный код доступенover on GitHub.