1. Знайомство з класами Query

До речі, ще один важливий момент — це допоміжний клас Query. Ти міг його бачити ось у цьому прикладі:


public List<Employee> getAllEmployees() {
    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> resultList = 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. Методи класу 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(). Про нього ми розповімо трохи докладніше.

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();