2.1 Знакомство с классами Query

Кстати, еще один важный момент – это вспомогательный класс Query. Ты мог его видеть вот в этом примере:

public List<Employee> getAllEmployes() {
    try (Session session = sessionFactory.openSession()) {
            Query<Employee> query = session.createQuery("from Employee", Employee.class);
            return query.list();
    }
}

На самом деле, Query – это интерфейс и у него есть несколько реализаций на разные случаи. Но для простоты я буду продолжать называть его классом. Это, скажем так, класс в широком смысле – в терминах ООП.

Примечание. Раньше было два класса:

  • Query для описания запроса.
  • TypedQuery для описания запроса с заранее известным типом.

Первый появился, когда Hibernate уже был, а дженериков еще не было. Потом, после выхода JDK 5, в Hibernate добавили еще один класс – TypedQuery, который уже поддерживал типизацию результата запроса.

Но, насколько я помню, начиная с 5-й версии Hibernate оставили только один типизированный класс, и он теперь называется Query.

Стандартный способ создания Query:

Query<Employee> query = session.createQuery("from Employee", Employee.class);

Объекты Query ты создавать научился, а как эти запросы выполнить?

Тут все еще проще – мы просто вызываем метод list() у объекта Query:

Query<Employee> query = session.createQuery("from Employee", Employee.class);
List<Employee> resultLіst = query.list();

У метода list() есть JPA-синоним, метод который делает тоже самое, но называется getResultList(). Ты можешь иногда встретить его в коде, написанном другими программистами.

Кстати, если запрос подразумевает, что результат будет в единственном результате, то для вызова запроса проще использовать метод uniqueResult().

Query<Employee> query = session.createQuery("from Employee where id = 1", Employee.class);
Employee result = query.uniqueResult();

У метода uniqueResult() есть JPA-синоним – метод singleResult(). Он появился для совместимости Hibernate со стандартом JPA. Делает он абсолютно то же самое.

2.2 Методы класса Query

На самом деле, у класса Query есть очень много различных методов. Ниже я расскажу еще о трех из них.

Во-первых, это метод stream(). И его JPA-синоним getResultStream().

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

Пример:

Query<Employee> query = session.createQuery("from Employee where id > 100", Employee.class);
Stream<Employee> stream = query.stream();

Второй метод – это метод executeUpdate(). Ты можешь написать запрос, который что-то изменит в базе данных. На этот случай нужно, чтобы Hibernate не использовал read-only транзакцию при обращении к базе данных.

Пример запроса: мы решили поднять уровень всех пользователей на 1.

Query<User> query = session.createQuery("update User set level=level+1", User.class);
int count = query.executeUpdate();

Метод executeUpdate() вернет количество строк, которые реально были изменены.

И наконец третий метод – это scroll(). О нем мы расскажем немного подробнее.

2.3 Методы класса Scroll

Этот метод чем-то похож на метод stream(). Только он позволяет перемещаться по списку результатов, не вытаскивая результаты вообще. То есть ты можешь выполнить запрос, потом проскролить его на миллионную строку результата и начать читать оттуда данные.

Такой продвинутый итератор.

Query<Employee> query = session.createQuery("from Employee where id > 100", Employee.class);
ScrollableResults<Employee> scroll = query.scroll();

У объекта ScrollableResults есть такие методы:

Метод Описание
R get() Возвращает текущий элемент
next() Перемещает указатель на следующий элемент
previous() Перемещает указатель на предыдущий элемент
scroll(int size) Скролит на size строк вперед
position(int pos) Делает текущим элементом элемент номер pos
last() Текущий элемент теперь последний
first() Текущий элемент теперь первый
getRowNumber() Возвращает номер текущей строки
setRowNumber() Устанавливает номер текущей строки

Допустим, ты выполнил запрос и хочешь получить последний элемент. Вот как это можно сделать:

Query<Employee> query = session.createQuery("from Employee where id > 100", Employee.class);
ScrollableResults<Employee> scroll = query.scroll();
scroll.last();
Employee lastEmployee = scroll.get();