JavaRush /Курсы /Модуль 4. Работа с БД /Изучаем класс Query

Изучаем класс Query

Модуль 4. Работа с БД
10 уровень , 1 лекция
Открыта

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();
1
Задача
Модуль 4. Работа с БД, 10 уровень, 1 лекция
Недоступна
Метод uniqueResult
Метод uniqueResult
1
Задача
Модуль 4. Работа с БД, 10 уровень, 1 лекция
Недоступна
Метод executeUpdate
Метод executeUpdate
Комментарии (17)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Artur Chakov Уровень 90
16 января 2026
Не понимаю, почему во второй задаче типизированный квери не принимается как правильный ответ (ведь UPDATE возвращает колличество обновленных строк) Query<Integer> query = session.createQuery("UPDATE Employee SET smth = concat('senior ', smth)", Integer.class);
Родион Уровень 113
9 августа 2025
мдаа, решаю значит задачку, все вроде правильно сделал - идея ничего не подчеркивает, да и по примерам все делал. Жмякаю "Проверить" - "задача не компилируется на сервере". Проверяю правильный ответ - все строчка в строчку, я честно 10 минут сидел и по буковкам все сверял - без толку. В итоге скопировал правильный ответ, вставил вместо своего - визуально вообще ничего не изменилось, однако валик пропустил. Чудеса, да и только...
Михаил Шапошников Уровень 1 Expert
10 апреля 2024
В версиях Hibernate, начиная с 6.0, введено явное разделение на два типа запросов: session.createQuery() используется для запросов на выборку данных (SELECT queries). Ты можешь использовать его для получения сущностей, списков сущностей или для выполнения запросов, которые возвращают проекции, например, части сущностей или агрегированные значения. session.createMutationQuery() используется для запросов, которые изменяют данные (так называемые мутационные операции, включающие INSERT, UPDATE, DELETE). Этот метод предназначен для создания запросов, которые непосредственно изменяют состояние данных в базе, не предназначены для выборки данных и могут привести к сайд-эффектам в базе данных.
Михаил Шапошников Уровень 1 Expert
10 апреля 2024
session.createQuery() для SELECT запроса

// Получение SessionFactory и открытие сессии
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
try (Session session = sessionFactory.openSession()) {
    // Начало транзакции
    Transaction transaction = session.beginTransaction();
    
    // Создание SELECT запроса
    String selectHql = "SELECT u FROM Users u";
    Query<Users> query = session.createQuery(selectHql, Users.class);
    List<Users> users = query.list();
    
    // Вывод информации о пользователях
    users.forEach(System.out::println);
    
    // Завершение транзакции
    transaction.commit();
}
Михаил Шапошников Уровень 1 Expert
10 апреля 2024
session.createMutationQuery() для UPDATE запроса

// Получение SessionFactory и открытие сессии
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
try (Session session = sessionFactory.openSession()) {
    // Начало транзакции
    Transaction transaction = session.beginTransaction();
    
    // Создание UPDATE запроса
    String updateHql = "UPDATE Users u SET u.name = :newName WHERE u.id = :id";
    MutationQuery updateQuery = session.createMutationQuery(updateHql);
    updateQuery.setParameter("newName", "Updated Name");
    updateQuery.setParameter("id", 1);
    
    // Выполнение обновления
    int affectedRows = updateQuery.executeUpdate();
    System.out.println("Количество обновленных записей: " + affectedRows);
    
    // Завершение транзакции
    transaction.commit();
}
Радомир Уровень 106 Expert
27 марта 2024
У меня одного из Idea задачи запускаются с ошибками? Хотя валидатор решение пропускает.
Andrew Cooper Уровень 1 Expert
9 ноября 2023

Query<User> query = session.createQuery("update User set level=level+1", User.class);
int count = query.executeUpdate();
и эти люди собрались кого-то учить... 🤦‍♀️💩
Михаил Уровень 111 Expert
12 ноября 2023
Спасибо. Проверил. Ты прав. А Как должно быть? у меня так работает: session.beginTransaction(); Query query = session.createQuery("update User set level=level+1"); int count = query.executeUpdate(); session.getTransaction().commit(); return count; Но ! @Deprecated Query createQuery(String var1);
Andrew Cooper Уровень 1 Expert
5 января 2024
давно это было, но по воспоминаниям там дженерик вроде бы нахрен никому не нужен )))
Кирилл Уровень 111 Expert
31 октября 2023
есть JPA-синоним – метод singleResult() - в JPA метод getSingleResult();
Надежда Уровень 104 Expert
13 сентября 2023
Не вводите в заблуждение. Query<User> query = session.createQuery("update User set level=level+1", User.class); int count = query.executeUpdate(); Поскольку это запрос на обновление, нам не нужно указывать тип возвращаемого объекта через дженерик, поскольку запрос на обновление (или удаление) не возвращает объекты нашего класса сущности. Правильно: Query query = session.createQuery("update User set level=level+1"); int count = query.executeUpdate();
Эльдар Уровень 108 Expert
2 октября 2023
Я тоже попался. Не могу понять что не так, вроде все как в лекции ввожу, валик не пропускает. Админы уберите дженерики!
Даниил Уровень 92 Expert
5 ноября 2023

            Transaction transaction = session.beginTransaction();
            int i = session.createQuery("update UserHQL set level = level + 1")
                    .executeUpdate();
            System.out.println("i = " + i);
            transaction.commit();
Руслан Уровень 79 Expert
6 апреля 2023
в десятках примеров до этой лекции использовался Query и тут его решили объяснить когда сам на других ресурсах выучил.очень странная последовательность подачи материалов. допустим мы начинали учить SQL и было просто слишком много заданий и лекций по каждой команде, но когда дошли до Hibernate то начинаются танцы с бубном и просто тупо дохера чегоне понятного начинают вводить без объяснений. сам изучаешь что к чему и тут на 30 лекции решили объяснить) логика вышла из чата)
Владимир Уровень 109 Expert
28 декабря 2022
task1003: Почему в запросе не нужно указывать класс в решении? мы же работаем в hql ? И в примере лекции указывается класс.
Stas S Уровень 108 Expert
28 ноября 2022
first() , last() и position: эти методы перемещают курсор(указатель), который указывает на элементы, но не трогают сами элементы.