4.1 Параметры к запросам

Hibernate позволяет передавать параметры запросам. Таким образом сильно упрощается вся работа с запросами и базой данных.

Очень редко можно встретить неизменяемые запросы. Вначале ведь кажется, что тебе нужно вернуть из базы просто список товаров. А потом выясняется, что нужен актуальный список товаров для определенного пользователя на определенную дату. Отсортированный по нужному полю, и еще не весь список, а определенная страница: например, товары с 21 по 30-й.

И именно эту задачу решают параметризированные запросы. Ты пишешь на HQL запрос, а потом значения, которые можно поменять заменяете на “специальные имена” – параметры. И потом отдельно при выполнении запроса можно передать значения этих параметров.

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


from EmployeeTask where employee.name = "Иван Иванович"

А теперь заменим имя на параметр:


from EmployeeTask where employee.name = :username

И вот как будет выглядеть наш Java-код для поиска задач:


String hql = "from EmployeeTask where employee.name = :username";
Query<EmployeeTask> query = session.createQuery( hql, EmployeeTask.class);
query.setParameter("username", "Иван Иванович");
List<EmployeeTask> resultLIst = query.list();

Также вместо имени параметр, можно использовать просто номер:


String hql = "from EmployeeTask where employee.name = :1";
Query<EmployeeTask> query = session.createQuery( hql, EmployeeTask.class);
query.setParameter(1, "Иван Иванович");
List<EmployeeTask> resultLIst = query.list();

Хотя лучше, конечно, использовать имя – читать и поддерживать такой код гораздо легче.

4.2 Метод setParameterList().

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

Как бы это можно было сделать:


String hql = "from EmployeeTask where occupation IN (:occupation_list)";
Query<EmployeeTask> query = session.createQuery( hql, EmployeeTask.class);
query.setParameterList("occupation_list", new String[] {"Программист", "Тестировщик"});
List<EmployeeTask> resultLIst = query.list();

В качестве значения параметра можно передать 4 вида списка:

  • массив объектов: Object[]
  • коллекция: Collection
  • типизированный массив: T[]
  • типизированная коллекция: Collection<T>

Если ты решил передавать типизированную коллекцию или массив, то тебе нужно передать тип данных третьим параметром. Пример:


String hql = "from EmployeeTask where occupation IN (:occupation_list)";
Query<EmployeeTask> query = session.createQuery( hql, EmployeeTask.class);
query.setParameterList("occupation_list", new String[] {"Программист", "Тестировщик"}, String.class);
List<EmployeeTask> resultLIst = query.list();

При работе с параметрами-списками также можно использовать номер вместо имени параметра. Но опять-таки с именем удобнее.

4.3 Защита от SQL Injection

Одно из важнейший назначений параметров – это защита базы от SQL-инъекций. Многие программисты-новички вместо использования параметров просто бы склеили строку из нескольких частей.

Вместо того, чтобы написать так:


String hql = "from EmployeeTask where employee.name = :username";
Query<EmployeeTask> query = session.createQuery( hql, EmployeeTask.class);
query.setParameter("username", "Иван Иванович");
List<EmployeeTask> resultLIst = query.list();

Написали бы так:


String hql = "from EmployeeTask where employee.name = " + "Иван Иванович";
Query<EmployeeTask> query = session.createQuery( hql, EmployeeTask.class);
List<EmployeeTask> resultLIst = query.list();

Никогда так не делайте! Никогда не склеивай SQL/HQL-запрос из нескольких частей. Потому что рано или поздно имя пользователя придет тебе с клиента. И злобный хакер в качестве имени клиента передаст вам строку типа ""Иван"; DROP TABLE user;"

И тогда твой запрос к базе данных примет вид:


from EmployeeTask where employee.name = "Иван"; DROP TABLE user;

И это еще хорошо, если твои данные просто удалят. Можно ведь написать и так:


from EmployeeTask where employee.name = "Иван";
UPDATE user SET password = '1' WHERE user.role = 'admin'

Или так:


from EmployeeTask where employee.name = "Иван";
UPDATE user SET role = 'admin' WHERE user.id = 123;
undefined
1
Задача
Модуль 4. Работа с БД, 10 уровень, 3 лекция
Недоступна
task1006
В методе getBetween получи сессию из MySessionFactory.getSessionFactory(). Напиши запрос на hql для получения списка...
undefined
1
Задача
Модуль 4. Работа с БД, 10 уровень, 3 лекция
Недоступна
task1007
В методе getIn получи сессию из MySessionFactory.getSessionFactory(). Напиши запрос на hql для получения списка Employee...