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;

ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ