JPA та сплячий режим - Критерії проти JPQL або HQL


295

Які плюси та мінуси використання критеріїв або HQL ? API критеріїв - це приємний об'єктно-орієнтований спосіб вираження запитів у сплячому режимі, але іноді Критерійні запити складніше зрозуміти / побудувати, ніж HQL.

Коли ви використовуєте критерії та коли HQL? Що ви віддаєте перевагу в яких випадках використання? Або це просто питання смаку?


Правильною відповіддю буде «залежить від випадку використання».
Хейс

А що з цим інструментом ? Це дозволяє побудувати загальні запити об'єктним способом: захищений пункт select () {return em.select ("DISTINCT i") .from (this.getName (), "i") .joinFetch ("i.locale lf") } public T findBySlug (String slug) {return (T) this.select () .join ("i.locale l"); .where ("l.slug =?", slug) .fetchSingle (); }
Войтех

1
Визначення питання, заснованого на думці, але люди не скористалися можливістю його закрити ... відповідно до поширених запитань на сайті

Відповіді:


212

Я переважно віддаю перевагу критеріям запитів для динамічних запитів. Наприклад, набагато простіше додати деякі замовлення динамічно або залишити деякі частини (наприклад, обмеження) поза залежно від певного параметра.

З іншого боку, я використовую HQL для статичних і складних запитів, тому що набагато простіше зрозуміти / прочитати HQL. Крім того, HQL трохи потужніший, я думаю, наприклад, для різних типів приєднання.


13
Крім того, хоча Критерії виглядають трохи більш безпечними для типів, єдине, що може змусити вас почувати себе в безпеці - це тестування.

Чи є хороші приклади, які показують, чому HQL в певних випадках кращий за критерії api? Я прочитав кінець одного блогу, але нічого не зрозумів. Будемо вдячні, якщо ви можете допомогти Дякую. Link - javalobby.org/articles/hibernatequery102
Ерран Morad

З усіх наведених вище причин - я також віддаю перевагу критеріям HQL, оскільки це безпечніше для програміста, зменшуючи помилки кодування - компіляція в рядку HQL не перевірена.
nuno

Однак існує проблема вилучення різних об'єктів під час створення сторінки. Роблячи це, я вибрав HQL, щоб уникнути проблем ...
Ентоні Вебстер,

використання запиту критеріїв з метамоделою для імен стовпців допомагає під час рефакторингу нічого не порушувати і за допомогою простої команди із сучасного IDE перейменувати всі події в коді.
Массімо

92

Існує різниця у продуктивності між HQL та критеріями Query, щоразу, коли ви запускаєте запит за допомогою критеріївQuery, він створює новий псевдонім для імені таблиці, який не відображається в останньому запитуваному кеші для будь-якої БД. Це призводить до накладних витрат на компіляцію згенерованого SQL, вимагає більше часу на його виконання.

Щодо стратегій отримання даних [http://www.hibernate.org/315.html]

  • Критерії дотримуються налаштувань лінь у ваших картах та гарантують, що завантажено те, що ви хочете. Це означає, що один запит щодо критеріїв може призвести до декількох негайних операторів SQL SELECT, щоб отримати підграф з усіма нелінивими асоційованими картами та колекціями. Якщо ви хочете змінити "як" і навіть "що", використовуйте setFetchMode (), щоб увімкнути або вимкнути зовнішнє отримання даних приєднання для певної колекції або асоціації. Критерійні запити також повністю відповідають стратегії отримання (приєднатись до вибору проти підселекту).
  • HQL поважає налаштування лінь у ваших картах і гарантує завантаження того, що ви хочете завантажити. Це означає, що один запит HQL може призвести до отримання декількох негайних операторів SQL SELECT, щоб отримати підграф з усіма нелінивими асоційованими картами та колекціями. Якщо ви хочете змінити "як" і навіть "що", використовуйте LEFT JOIN FETCH, щоб увімкнути зовнішнє приєднання для певної колекції або звести об'єднання "багато в один" або "один на один", або "ПРИЄДНУЙТЕ ФЕТЧ", щоб увімкнути внутрішнє отримання приєднання для ненульового об'єднання «багато в один» або «один на один». HQL-запити не поважають жодного fetch = "приєднання", визначеного в документі відображення.

1
Просто вказуючи на когось, хто переглядає. що ця відповідь є з 2008 р., можливо, це вже не так. dimovelev.blogspot.com/2015/02/…
Amalgovinus

41

Критерії - це об'єктно-орієнтований API, тоді як HQL означає об'єднання рядків. Це означає, що всі переваги об'єктно-орієнтованості застосовуються:

  1. За умови рівності версія OO дещо менш схильна до помилок. Будь-який старий рядок може бути доданий до запиту HQL, тоді як лише дійсні об’єкти Критерії можуть перетворити його у дерево критеріїв. Ефективно, класи критеріїв більш обмежені.
  2. З автоматичним завершенням OO є більш відкритим (і, таким чином, простішим у використанні, принаймні для мене). Вам не обов’язково пам'ятати, які частини запиту йдуть куди; IDE може вам допомогти
  3. Вам також не потрібно запам’ятовувати деталі синтаксису (наприклад, які символи куди йдуть). Все, що вам потрібно знати, - це викликати методи та створювати об’єкти.

Оскільки HQL дуже схожий на SQL (який більшість розробників уже дуже добре знають), ці аргументи "не повинні пам'ятати" не мають такої ваги. Якби HQL був іншим, то це було б більш важливим.


12
Ці аргументи не мають сили (щодо HQL). Він не повинен включати конкатенацію рядків. Що версія OO менш схильна до помилок, необгрунтовано. Він однаково схильний до помилок, але іншого типу. Намагання знати, які методи викликати, не так сильно відрізняється від того, щоб знати, які символи викликати в HQL (я маю на увазі, серйозно, тут ми не
вирішуємо

Чи є хороші приклади, які показують, чому HQL в певних випадках кращий за критерії api? Я прочитав кінець одного блогу, але нічого не зрозумів. Будемо вдячні, якщо ви можете допомогти Дякую. Link - javalobby.org/articles/hibernatequery102
Ерран Morad

1
Запити з іменем HQL складаються під час розгортання і в цей момент відсутні поля (можливо, для поганих рефакторів?). Я думаю, що це робить код більш стійким і насправді менш схильним до помилок, ніж критерії.
нардук

Автоматичне завершення в критеріях майже марно, оскільки властивості - це лише рядки.
Lluis Martinez

35

Зазвичай я використовую критерії, коли я не знаю, які вхідні дані будуть використані на яких фрагментах даних. Як і у формі пошуку, де користувач може ввести будь-який від 1 до 50 елементів, і я не знаю, що він буде шукати. Дуже просто додати більше критеріїв, коли я переглядаю, що користувач шукає. Я думаю, було б трохи складніше ставити запит HQL у цій обставині. HQL - це чудово, хоча коли я точно знаю, чого хочу.


1
Це хороший коментар. В даний час ми будуємо дуже великі рядки HQL для форми пошуку, яка містить безліч різних об'єктів через приєднання. Виглядає некрасиво. Збираємось перевірити, чи може Критерій це очистити. Цікаво ...
cbmeeks

Дякую. Це відмінний приклад. Ви можете, будь ласка, дати мені ще трохи?
Ерран Морад

31

HQL набагато легше читати, простіше налагоджувати за допомогою таких інструментів, як плагін Eclipse Hibernate, і легше реєструватися. Критерійні запити краще для побудови динамічних запитів, де велика кількість поведінки визначається під час виконання. Якщо ви не знаєте SQL, я міг би зрозуміти, використовуючи запити щодо критеріїв, але в цілому я віддаю перевагу HQL, якщо знаю, що хочу заздалегідь.


22

Критерії - це єдиний спосіб вказати пошук природних ключів, які використовують перевагу спеціальної оптимізації в кеші запитів другого рівня. HQL не має жодного способу вказати необхідний підказку.

Ви можете знайти більше інформації тут:


21

Критерії Апі - одна з хороших концепцій сплячки. на мою думку, це декілька моментів, за допомогою яких ми можемо різнитися між HQL та критеріями Api

  1. HQL призначений для виконання операцій вибору та не виділення даних, але Критерії призначені лише для вибору даних, ми не можемо виконувати операції з невибору з використанням критеріїв.
  2. HQL підходить для виконання статичних запитів, де Критерії підходять для виконання динамічних запитів
  3. HQL не підтримує концепцію сторінки , але ми можемо домогтися сторінки з критеріями.
  4. Критерії, які використовуються для виконання більше часу, ніж HQL.
  5. З критеріями ми захищені від SQL Injection через її генерацію динамічних запитів, але в HQL, оскільки ваші запити є фіксованими або параметризованими, немає безпеки від SQL Injection

11
limit offset:rows Кілька пунктів Пагинація є в HQL: ви можете використовувати In hql, ви можете уникнути введення sql, використовуючиsetParameter
Viswanath Lekshmanan

13

Щоб використовувати найкраще з обох світів, виразність та стислість HQL та динамічний характер Критеріїв розглянути можливість використання Querydsl .

Querydsl підтримує JPA / Hibernate, JDO, SQL та Collections.

Я підтримую Querydsl, тому ця відповідь упереджена.


13

Для мене Критерії - це досить легко зрозуміти і робити динамічні запити. Але недолік, про який я зараз кажу, полягає в тому, що він завантажує всі відносини багато-один і т.д., тому що у нас є лише три типи FetchModes, тобто Select, Proxy і Default, і в усіх цих випадках він завантажує багато-одного (можливо, я помиляюся, якщо так допомогти мене виходять :))

Друга проблема з критеріями полягає в тому, що він завантажує повний об'єкт, тобто, якщо я хочу просто завантажити EmpName працівника, він не зможе придумати це, придумав, що він створив повний об'єкт Employee, і я можу отримати EmpName від нього, завдяки цьому він справді погано працює в звітність . де HQL просто завантажує (не завантажував асоціації / відносини), те, що ви хочете, так збільшуйте продуктивність у багато разів.

Однією з особливостей критеріїв є те, що він захистить u від SQL Injection через його динамічну генерацію запитів, де, як і в HQL, ур-запити є фіксованими або параметризованими, тому вони не є безпечними від ін'єкції SQL.

Крім того, якщо ви пишете HQL у файли ur aspx.cs, то ви щільно поєднані з ур DAL.

В цілому мій висновок полягає в тому, що є місця, де ти не можеш жити без таких звітів, як HQL, тому використовувати їх ще Критерії простіше в управлінні.


13
HQL НЕ безпечний для ін'єкцій SQL
Варун Мехта

Я думаю, що Критерії не є безпечними для ін'єкцій. Дивіться мій пост тут: stackoverflow.com/questions/6746486/…
Містер Сміт

4
HQL IS sql безпечний для ін'єкцій, додавши "setParameter"
Javatar

2
@Zafar: за допомогою проекцій можна вибрати лише певні властивості сутності
Răzvan Flavius ​​Panda

@Zafar ви можете встановити проекцію в запиті критеріїв для вибору конкретних стовпців. Ви можете отримати EmpName, не потрібно отримувати повний об'єкт.
Хатрі

12

API критеріїв

API критеріїв краще підходить для динамічно генерованих запитів. Отже, якщо ви хочете додати фільтри пропозицій WHERE, ПРИЄДНУЙТЕСЯ або змінюючи пункт ORDER BY або стовпці проекцій, API API може допомогти вам динамічно генерувати запит таким чином, що також запобігає атакам SQL Injection .

З іншого боку, запити щодо критеріїв менш експресивні і навіть можуть призвести до дуже складних і неефективних SQL запитів, як пояснено в цій статті .

JPQL та HQL

JPQL - це стандартна мова запитів для юридичної особи JPA, тоді як HQL розширює JPQL і додає деякі особливості, пов’язані зі сном.

JPQL і HQL дуже виразні і нагадують SQL. На відміну від API критеріїв, JPQL та HQL спрощують передбачення базового запиту SQL, що генерується постачальником JPA. Так само набагато простіше переглядати запити HQL, ніж критерії.

Варто зазначити, що вибирати об’єкти з API JPQL або Criteria має сенс, якщо вам потрібно змінити їх. В іншому випадку проекція DTO є набагато кращим вибором.

Висновок

Якщо вам не потрібно змінювати структуру запитів сутності, використовуйте JPQL або HQL. Якщо вам потрібно змінити критерії фільтрування або сортування або змінити проекцію, то використовуйте API критеріїв.

Однак, оскільки ви використовуєте JPA або Hibernate, це не означає, що ви не повинні використовувати нативний SQL. SQL запити дуже корисні, а JPQL і API критеріїв не є заміною для SQL. Перегляньте цю статтю, щоб дізнатися більше про цю тему



11

Для мене найбільший виграш у Критеріях - API API, де ви можете передавати об’єкт і в сплячку будувати запит на основі цих властивостей об'єкта.

Крім того, API критеріїв має свої химерності (я вважаю, що спляча команда переробляє api), наприклад:

  • критерії.createAlias ​​("obj") примушує внутрішнє з'єднання замість можливого зовнішнього з'єднання
  • ви не можете створити один і той же псевдонім два рази
  • деякі пропозиції sql не мають простих критеріїв (наприклад, під вибір)
  • тощо.

Я схильний використовувати HQL, коли хочу запити, схожі на sql (видалити з користувачів, де status = 'заблоковано'), і я схильний використовувати критерії, коли я не хочу використовувати додавання рядків.

Ще одна перевага HQL полягає в тому, що ви можете визначити всі свої запити перед рукою і навіть екстерналізувати їх у файл чи так.


9

Критерії api забезпечують одну відмінну особливість, яку не надає ні SQL, ні HQL. тобто. це дозволяє перевірити час запиту для складання.


7

На початку ми використовували в основному критерії в нашому додатку, але після його заміни на HQL через проблеми з продуктивністю.
В основному ми використовуємо дуже складні запити з кількома приєднаннями, що призводить до декількох запитів у Критеріях, але дуже оптимізовано в HQL.
Справа в тому, що ми використовуємо лише кілька властивостей конкретного об'єкта, а не повноцінні об'єкти. З критеріями проблема полягала і в конкатенації рядків.
Скажімо, якщо вам потрібно відображати ім'я та прізвище користувача в HQL, це досить просто, (name || ' ' || surname)але в Crteria це неможливо.
Для подолання цього ми використовували ResultTransormers, де існували методи, в яких така конкатенація реалізована для необхідного результату.
Сьогодні ми в основному використовуємо HQL так:

String hql = "select " +
            "c.uuid as uuid," +
            "c.name as name," +
            "c.objective as objective," +
            "c.startDate as startDate," +
            "c.endDate as endDate," +
            "c.description as description," +
            "s.status as status," +
            "t.type as type " +
            "from " + Campaign.class.getName() + " c " +
            "left join c.type t " +
            "left join c.status s";

Query query =  hibernateTemplate.getSessionFactory().getCurrentSession().getSession(EntityMode.MAP).createQuery(hql);
query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
return query.list();

тому в нашому випадку повернуті записи - це карти потрібних властивостей.


1
За допомогою критеріїв ви можете використовувати org.hibernate.criterion.CriteriaSpecification.ALIAS_TO_ENTITY_MAP
AA.

Повернення списку карт на мій досвід має дуже погані показники. Я вважаю за краще повертати список масивів об'єктів або списки бобів (ви завжди можете визначити квасоля, яка відповідає вашому конкретному набору результатів).
Lluis Martinez

7
  • HQL призначений для виконання операцій вибору та невибору даних, але Критерії призначені лише для вибору даних, ми не можемо виконувати операції, що не вибираються, використовуючи критерії
  • HQL підходить для виконання статичних запитів, де Критерії підходять для виконання динамічних запитів
  • HQL не підтримує концепцію сторінки, але ми можемо домогтися сторінки з критеріями
  • Критерії використовували більше часу для виконання, ніж HQL
  • З критеріями ми захищені від SQL Injection через її динамічну генерацію запитів, але в HQL, оскільки ваші запити є фіксованими або параметризованими, немає безпеки від SQL Injection.

джерело


Для уточнення, запити щодо критеріїв за допомогою API критеріїв Hibernate можуть бути доступні для запитів, але запити критеріїв JPA охоплюють вибір, оновлення та видалення. Дивіться CriteriaUpdate<T>та CriteriaDelete<T>для довідок.
Нарос

5

Критерійний запит для динамічного ми можемо побудувати запит на основі наших входів. У випадку Hql запит - це статичний запит, коли ми будуємо, ми не можемо змінити структуру запиту.


2
Не так. За допомогою HQL ви можете встановити властивості за допомогою ідентифікатора ':', а потім замінити ці властивості унікальними значеннями. Наприклад, Query q = session.createQuery ("SELECT: aValue FROM my_table"); а потім q.setParameter ("aValue", "some_column_name");
MattC

@MattC У своєму прикладі ви змінюєте значення параметрів, а не структуру запиту.
Цар

4

Я не хочу тут бити мертвого коня, але важливо згадати, що запити щодо критеріїв тепер застарілі. Використовуйте HQL.


1

Я також віддаю перевагу критеріям запитів для динамічних запитів. Але я віддаю перевагу hql для запитів на видалення, наприклад, якщо видалити всі записи з дочірньої таблиці для батьківського ідентифікатора 'xyz', це легко досягти HQL, але для API критеріїв спершу ми повинні запустити n кількість запитів на видалення, де n - кількість дитини табличні записи.


0

Більшість відповідей тут вводять в оману і згадують, що Criteria Queriesвони повільніші, ніж HQLнасправді не так.

Якщо ви глибоко заглибитесь і виконаєте деякі тести, ви побачите, що Критерійні запити працюють набагато краще, ніж звичайний HQL .

А також із запитом критеріїв ви отримуєте об'єктно-орієнтоване управління, якого немає у HQL .

Для отримання додаткової інформації читайте цю відповідь тут .


0

Є й інший спосіб. Я закінчив створення HQL-аналізатора, заснованого на сплячому оригінальному синтаксисі, щоб він спершу проаналізував HQL, після чого він міг динамічно вводити динамічні параметри або автоматично додавати деякі загальні фільтри для запитів HQL. Це чудово працює!


0

Ця посада досить стара. Більшість відповідей говорять про критерії сплячки, а не про критерії СВ. JPA 2.1 додав CriteriaDelete / CriteriaUpdate та EntityGraph, який контролює, що саме потрібно отримати. API критеріїв кращий, оскільки Java є OO. Саме тому створюється JPA. Коли компілюється JPQL, він буде переведений на дерево AST (модель OO), перш ніж перевести його на SQL.


-3

HQL може спричинити занепокоєння з безпеки, як-от введення SQL.


11
Ці проблеми викликані не HQL, а нерозумінням основних практик розробки програмного забезпечення. Я також можу створити код, схильний до sql-ін'єкційних атак з критеріями api.
Jens Schauder

1
Це як би сказати, що "запит на RDBMS з Java може викликати проблеми безпеки ін'єкцій SQL": D
Цар
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.