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

Хоча краще, звісно, використовувати ім'я — читати та підтримувати такий код набагато легше.

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

Під час використання параметрів-списків також можна використовувати номер замість імені параметра. Але знову ж таки, з ім'ям зручніше.

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;