Питання 26 · Розділ 16

Що таке JPQL і чим він відрізняється від SQL

JPQL (Java Persistence Query Language) — об'єктно-орієнтований мову запитів, який працює з сутностями та їх полями, а не з таблицями та колонками. Розуміння відмінностей між JPQ...

Мовні версії: English Russian Ukrainian

Огляд

JPQL (Java Persistence Query Language) — об’єктно-орієнтований мову запитів, який працює з сутностями та їх полями, а не з таблицями та колонками. Розуміння відмінностей між JPQL та SQL критично важливе для ефективної роботи з JPA.


🟢 Junior Level

Що таке JPQL

JPQL — мова запитів, яка працює з сутностями та полями, а не з таблицями та колонками.

// JPQL — працює з entity класами
List<User> users = entityManager.createQuery(
    "SELECT u FROM User u WHERE u.age > :age", User.class)
    .setParameter("age", 18)
    .getResultList();

// SQL — працює з таблицями
// SELECT * FROM users WHERE age > 18;

Основні відмінності

JPQL SQL
User (entity class) users (table name)
u.age (field name) age (column name)
u.userProfile.city (навігація) JOIN user_profiles ON ...
Database-agnostic Database-specific
Автоматично генерує SQL Прямий SQL

Параметризація

// ✅ Named parameters (рекомендується)
@Query("SELECT u FROM User u WHERE u.name = :name AND u.age > :age")
List<User> find(@Param("name") String name, @Param("age") int age);

// ❌ String concatenation (SQL injection!)
"SELECT u FROM User u WHERE u.name = '" + name + "'"  // ❌

🟡 Middle Level

JPQL vs SQL — детальне порівняння

JPQL:
- Працює з entities та полями
- Database-agnostic (працює з будь-якою БД)
- Автоматично генерує SQL
- Підтримує поліморфні запити
- Працює з наслідуванням

SQL:
- Працює з таблицями та колонками
- Database-specific (синтаксис залежить від БД)
- Повний контроль над запитом
- Немає автоматичного маппінгу

Native SQL — коли потрібен

// Database-specific функції
List<User> users = entityManager.createNativeQuery(
    "SELECT * FROM users WHERE created_at > NOW() - INTERVAL '30 days'",
    User.class
).getResultList();

// CTE (Common Table Expressions)
List<User> users = entityManager.createNativeQuery("""
    WITH recent_orders AS (
        SELECT user_id, MAX(created_at) as last_order
        FROM orders GROUP BY user_id
    )
    SELECT u.* FROM users u JOIN recent_orders ro ON u.id = ro.user_id
    WHERE ro.last_order > :date
    """, User.class).setParameter("date", date).getResultList();

🔴 Senior Level

JPQL та наслідування

// Поліморфний запит — включає всі підкласи
SELECT p FROM Payment p  // CardPayment, CashPayment, CryptoPayment

// З TYPE — фільтр по підкласу
SELECT p FROM Payment p WHERE TYPE(p) = CardPayment

// З TREAT — cast до підкласу
SELECT p FROM Payment p JOIN TREAT(p AS CardPayment) cp WHERE cp.cardNumber = :number

Коли використовувати JPQL vs SQL

JPQL:
✅ Database-agnostic запити
✅ Прості та середні запити
✅ Коли потрібна поліморфність
✅ Коли працюєте з entities

Native SQL:
✅ Database-specific функції (CTE, window functions)
✅ Складні аналітичні запити
✅ Bulk operations (UPDATE/DELETE тисяч записів)
✅ Коли JPQL не підтримує синтаксис

Best Practices

✅ JPQL для database-agnostic запитів
✅ Native SQL для database-specific запитів
✅ Parameterized queries (не concat!)
✅ DTO projection для read-only
✅ JOIN FETCH для пов'язаних даних

❌ Concat для параметрів (SQL injection!)
❌ JPQL для складних database-specific запитів
❌ Завантаження повних entities для read-only

🎯 Шпаргалка для співбесіди

Обов’язково знати:

  • JPQL працює з сутностями та полями, SQL — з таблицями та колонками
  • JPQL database-agnostic (працює з будь-якою БД), SQL — database-specific
  • Параметризація обов’язкова: :name (named parameters), НЕ string concat (SQL injection!)
  • Native SQL потрібен для: CTE, window functions, bulk operations, database-specific функцій
  • DTO projection в JPQL через конструктор: SELECT new com.example.Dto(…)

Пов’язані теми:

  • [[27. Що таке Criteria API і коли його використовувати]]
  • [[28. Як використовувати JOIN FETCH для вирішення проблеми N+1]]
  • [[29. Що таке projection в JPA]]
  • [[30. Які типи наслідування підтримує JPA]]