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;