JPA и Hibernate - критерии против JPQL или HQL

295

Каковы плюсы и минусы использования Criteria или HQL ? Criteria API - это хороший объектно-ориентированный способ выражения запросов в Hibernate, но иногда Criteria Queries труднее понять / построить, чем HQL.

Когда вы используете критерии и когда HQL? Что вы предпочитаете в каких случаях? Или это просто вопрос вкуса?

cretzel
источник
Правильный ответ будет «зависит от варианта использования».
Hace
А как насчет этого инструмента ? Он позволяет создавать общие запросы объектным способом: защищенное предложение 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
Определение вопроса, основанного на мнении, но люди не воспользовались возможностью, чтобы закрыть его ... согласно FAQ сайта

Ответы:

212

Я в основном предпочитаю Criteria Queries для динамических запросов. Например, гораздо проще динамически добавлять порядок или не учитывать некоторые части (например, ограничения) в зависимости от какого-либо параметра.

С другой стороны, я использую HQL для статических и сложных запросов, потому что намного легче понять / прочитать HQL. Кроме того, я думаю, что HQL немного мощнее, например, для разных типов соединений.

cretzel
источник
13
Кроме того, хотя критерии выглядят более безопасными, единственное, что может помочь вам чувствовать себя в безопасности, - это тестирование.
Есть ли хорошие примеры, которые показывают, почему HQL лучше, чем критерии api в некоторых случаях? Я прочитал конец одного блога, но ничего не понял. Был бы признателен, если бы вы могли помочь. Спасибо. Ссылка - javalobby.org/articles/hibernatequery102
Эрран Морад
Все вышеперечисленные причины - я также предпочитаю Criteria HQL, потому что это безопаснее для программиста, уменьшая ошибки кодирования - компиляция строки HQL не проверяется.
Нуно
Тем не менее, существует проблема извлечения отдельных объектов во время нумерации страниц. При этом я бы выбрал HQL, чтобы избежать проблем ...
Энтони Вебстер
Использование запроса критериев с метамоделью для имен столбцов помогает во время рефакторинга ничего не нарушать и с помощью простой команды из современной IDE переименовывает все вхождения в коде.
Массимо
92

Существует разница с точки зрения производительности между HQL и testsQuery, каждый раз, когда вы запускаете запрос с помощью attributeQuery, он создает новый псевдоним для имени таблицы, который не отражается в последнем кеше для любой БД. Это приводит к накладным расходам на компиляцию сгенерированного SQL, что требует больше времени для выполнения.

Относительно стратегий извлечения [http://www.hibernate.org/315.html]

  • Критерии учитывают настройки лени в ваших сопоставлениях и гарантируют, что то, что вы хотите загрузить, загружено. Это означает, что один запрос Criteria может привести к нескольким SQL-запросам SELECT, чтобы выбрать подграф со всеми сопоставленными сопоставлениями и коллекциями. Если вы хотите изменить «как» и даже «что», используйте setFetchMode (), чтобы включить или отключить выборку внешнего соединения для конкретной коллекции или ассоциации. Запросы по критериям также полностью соответствуют стратегии выборки (объединение против выбора против подраздела).
  • HQL учитывает настройки лени в ваших отображениях и гарантирует загрузку того, что вы хотите загрузить. Это означает, что один запрос HQL может привести к нескольким SQL-запросам SELECT, чтобы выбрать подграф со всеми сопоставлениями и коллекциями, которые не ленивые. Если вы хотите изменить «как» и даже «что», используйте LEFT JOIN FETCH, чтобы включить выборку внешнего соединения для конкретной коллекции или обнуляемую ассоциацию «многие к одному» или «один к одному», или «JOIN FETCH», чтобы включить выборка внутреннего соединения для необнуляемой связи «многие к одному» или «один к одному». HQL-запросы не учитывают никаких fetch = "join", определенных в документе сопоставления.
Варун Мехта
источник
1
Просто указывая на тех, кто просматривает. что этот ответ с 2008 года. это может быть не так больше. dimovelev.blogspot.com/2015/02/…
Амальговинус
41

Критерии - это объектно-ориентированный API, а HQL означает конкатенацию строк. Это означает, что применяются все преимущества объектно-ориентированного подхода:

  1. При прочих равных версия OO несколько менее подвержена ошибкам. Любая старая строка может быть добавлена ​​в запрос HQL, тогда как только допустимые объекты Criteria могут превратить ее в дерево Criteria. По сути, классы Критерии более ограничены.
  2. С автозаполнением ОО является более обнаружимым (и, следовательно, более простым в использовании, по крайней мере для меня). Вам не обязательно помнить, какие части запроса идут куда; IDE может помочь вам
  3. Вам также не нужно запоминать особенности синтаксиса (например, какие символы куда идут). Все, что вам нужно знать, это как вызывать методы и создавать объекты.

Поскольку HQL очень похож на SQL (который большинство разработчиков уже хорошо знают), эти аргументы «не должны помнить» не имеют большого веса. Если бы HQL был более разным, то это было бы более важным.

Крейг Уокер
источник
12
Эти аргументы не выдерживают критики (по отношению к HQL). Это не должно включать конкатенацию строк. То, что версия OO менее подвержена ошибкам, необоснованно. В равной степени подвержен ошибкам, но другого рода. Усилие узнать, какие методы вызывать, не сильно отличается от знания того, какие символы вызывать в HQL (я имею в виду, серьезно, мы не решаем PDE здесь.)
luis.espinal
Есть ли хорошие примеры, которые показывают, почему HQL лучше, чем критерии api в некоторых случаях? Я прочитал конец одного блога, но ничего не понял. Был бы признателен, если бы вы могли помочь. Спасибо. Ссылка - javalobby.org/articles/hibernatequery102
Эрран Морад
1
Именованные запросы HQL компилируются во время развертывания, и в этот момент обнаруживаются пропущенные поля (может быть, для плохих рефакторов?). Я думаю, что это делает код более устойчивым и фактически менее подверженным ошибкам, чем критерии.
Нардук
Автозаполнение в Criteria практически бесполезно, потому что свойства - это просто строки.
Луис Мартинес
35

Я обычно использую Критерии, когда я не знаю, какие данные будут использоваться для ввода данных. Как и в форме поиска, где пользователь может вводить от 1 до 50 элементов, и я не знаю, что они будут искать. Очень просто добавить больше критериев, когда я проверяю, что ищет пользователь. Я думаю, что было бы немного сложнее поставить HQL-запрос в таких обстоятельствах. HQL - это здорово, когда я точно знаю, чего хочу.

Артур Томас
источник
1
Это хороший комментарий. В настоящее время мы создаем очень большие строки HQL для формы поиска, которая содержит много различных объектов через объединения. Выглядит некрасиво Посмотрим, сможет ли Критерий это убрать. Интересно ...
cbmeeks
Спасибо. Это отличный пример. Можете ли вы дать мне еще немного?
Эрран Морад
31

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

Брайан Детерлинг
источник
22

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

Вы можете найти больше информации здесь:

Алекс Миллер
источник
21

Критерии Api - одна из хороших концепций Hibernate. по моему мнению, это несколько моментов, с помощью которых мы можем сделать разницу между HQL и Criteria Api

  1. HQL должен выполнять как операции выбора, так и выбора без выбора над данными, но Критерии предназначены только для выбора данных, мы не можем выполнять операции без выбора, используя критерии.
  2. HQL подходит для выполнения статических запросов, в то время как критерии подходят для выполнения динамических запросов.
  3. HQL не поддерживает концепцию разбиения на страницы , но мы можем добиться разбиения на страницы с помощью критериев.
  4. Критерии раньше выполнялись дольше, чем HQL.
  5. С Критериями мы безопасны с SQL-инъекцией из-за его динамической генерации запросов, но в HQL, поскольку ваши запросы являются либо фиксированными, либо параметризованными, нет никакой защиты от SQL-инъекции
Эрвинд
источник
11
Пара точек Разбивка есть в HQL: вы можете использовать limit offset:rows в HQL можно избежать с помощью SQL - инъекцииsetParameter
Viswanath Lekshmanan
13

Чтобы использовать лучшее из обоих миров, выразительность и лаконичность HQL, а также динамический характер критериев рассмотрите возможность использования Querydsl .

Querydsl поддерживает JPA / Hibernate, JDO, SQL и коллекции.

Я поддерживаю Querydsl, поэтому этот ответ предвзят.

Тимо Весткэмпер
источник
13

Для меня Критерии довольно легко понять и делать динамические запросы. Но недостаток, который я до сих пор говорю, заключается в том, что он загружает все отношения многие-один и т. Д., Потому что у нас есть только три типа FetchModes, то есть Select, Proxy и Default, и во всех этих случаях он загружает многие-один (может быть, я ошибаюсь, если это поможет меня нет :))

Вторая проблема с критериями заключается в том, что он загружает полный объект, т. Е. Если я хочу просто загрузить EmpName сотрудника, он не придет с этим, он придет с полным объектом Employee, и я смогу получить из него EmpName, потому что он действительно плохо работает в отчетность . где, поскольку HQL просто загружает (не загружает ассоциации / отношения) то, что вы хотите, так многократно увеличьте производительность.

Одной из особенностей Criteria является то, что он будет защищать вас от SQL-инъекций из-за динамической генерации запросов, где, как и в HQL, поскольку ваши запросы являются либо фиксированными, либо параметризованными, поэтому они не защищены от SQL-инъекции.

Кроме того, если вы пишете HQL в файлах ur aspx.cs, то вы тесно связаны с вашим DAL.

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

Зафар
источник
13
HQL НЕ безопасен для SQL-инъекций
Varun Mehta
Я думаю, что критерии не безопасны для инъекций. Смотрите мой пост здесь: stackoverflow.com/questions/6746486/…
Мистер Смит
4
HQL IS sql безопасен для инъекций, добавив setParameter
Javatar
2
@Zafar: вы можете выбрать только определенные свойства объекта, используя проекции
Răzvan Flavius ​​Panda
@Zafar вы можете установить проекцию в запросе критериев для выбора определенных столбцов. Вы можете получить EmpName, нет необходимости извлекать полный объект.
Хатри
12

Критерии API

Criteria API лучше подходит для динамически генерируемых запросов. Таким образом, если вы хотите добавить фильтры предложений WHERE, предложения JOIN или изменить предложение ORDER BY или столбцы проекции, то API Criteria может помочь вам динамически генерировать запрос таким образом, чтобы также предотвратить атаки SQL-инъекций .

С другой стороны, запросы Criteria менее выразительны и могут даже привести к очень сложным и неэффективным запросам SQL, как объясняется в этой статье .

JPQL и HQL

JPQL - это стандартный язык запросов сущностей JPA, в то время как HQL расширяет JPQL и добавляет некоторые специфичные для Hibernate функции.

JPQL и HQL очень выразительны и напоминают SQL. В отличие от Criteria API, JPQL и HQL упрощают прогнозирование базового SQL-запроса, генерируемого поставщиком JPA. Также гораздо проще просматривать свои HQL-запросы, чем критерии.

Стоит отметить, что выбор сущностей с помощью JPQL или Criteria API имеет смысл, если вам нужно изменить их. В противном случае, прогноз DTO является гораздо лучшим выбором.

Вывод

Если вам не нужно изменять структуру запроса сущности, используйте JPQL или HQL. Если вам нужно изменить критерии фильтрации или сортировки или изменить прогноз, используйте Criteria API.

Однако то, что вы используете JPA или Hibernate, не означает, что вам не следует использовать собственный SQL. SQL-запросы очень полезны, и JPQL и Criteria API не являются заменой SQL. Проверьте эту статью для более подробной информации по этой теме.

Влад Михалча
источник
11

Для меня самая большая победа в Criteria - это API-интерфейс примеров, где вы можете передать объект, а hibernate создаст запрос на основе этих свойств объекта.

Кроме того, у API критериев есть свои особенности (я считаю, что команда hibernate перерабатывает API), например:

  • a attribute.createAlias ​​("obj") вызывает внутреннее соединение вместо возможного внешнего соединения
  • вы не можете создать один и тот же псевдоним два раза
  • Некоторые SQL-предложения не имеют простого критерия соответствия (например, выборка)
  • и т.п.

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

Еще одним преимуществом HQL является то, что вы можете определить все свои запросы заранее и даже экспортировать их в файл или около того.

Мигель Пинг
источник
9

Критерии API предоставляют одну особенность, которую не предоставляет ни SQL, ни HQL. то есть. это позволяет проверять время компиляции запроса.

user1165443
источник
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.
Возвращение списка карт по моему опыту имеет очень плохую производительность. Я предпочитаю возвращать список массивов объектов или списков bean-компонентов (вы всегда можете определить bean-компонент, соответствующий вашему конкретному набору результатов)
Луис Мартинес
7
  • HQL должен выполнять операции выбора и выбора данных, но Критерии предназначены только для выбора данных, мы не можем выполнять операции выбора, используя критерии
  • HQL подходит для выполнения статических запросов, в то время как критерии подходят для выполнения динамических запросов.
  • HQL не поддерживает концепцию разбиения на страницы, но мы можем добиться разбиения на страницы с помощью критериев
  • Критерии раньше занимали больше времени, чем выполнение HQL
  • С Критериями мы безопасны с SQL-инъекцией из-за его динамической генерации запросов, но в HQL, поскольку ваши запросы являются либо фиксированными, либо параметризованными, от SQL-инъекции нет никакой защиты.

источник

Premraj
источник
Чтобы уточнить, запросы критериев с использованием API Критерии Hibernate могут быть доступны для запросов, но запросы критериев JPA охватывают выборки, обновления и удаления. Смотрите CriteriaUpdate<T>и CriteriaDelete<T>для справки.
Нарос
5

Критерии запроса для динамически мы можем построить запрос на основе наших входных данных. В случае Hql-запроса является статическим запросом, как только мы создаем, мы не можем изменить структуру запроса.

user1679378
источник
2
Не так. В HQL вы можете установить свойства с идентификатором ':', а затем заменить эти свойства уникальными значениями. Например, Query q = session.createQuery ("SELECT: aValue FROM my_table"); а затем q.setParameter ("aValue", "some_column_name");
MattC
@MattC В вашем примере вы изменяете значения параметров, а не структуру запроса.
Царь
4

Я не хочу пнуть здесь мертвую лошадь, но важно отметить, что запросы Criteria в настоящее время устарели. Используйте HQL.

Eskir
источник
1

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

Пунит Патель
источник
0

Большинство ответов здесь вводят в заблуждение и упоминают, что Criteria Queriesони медленнее, чем это HQL, на самом деле это не так.

Если вы углубитесь и выполните некоторые тесты, вы увидите, что Criteria Queries работают намного лучше, чем обычный HQL .

А также с Criteria Query вы получаете объектно-ориентированное управление, которого нет в HQL .

Для получения дополнительной информации прочитайте этот ответ здесь .

Притам Банерджи
источник
0

Есть другой способ. Я закончил с созданием синтаксического анализатора HQL на основе оригинального синтаксиса hibernate, чтобы он сначала анализировал HQL, а затем мог динамически вводить динамические параметры или автоматически добавлять некоторые общие фильтры для запросов HQL. Работает отлично!

Уоллес Пэн
источник
0

Этот пост довольно старый. Большинство ответов говорят о критериях Hibernate, а не о критериях JPA. В JPA 2.1 добавлены CriteriaDelete / CriteriaUpdate и EntityGraph, которые определяют, что именно нужно получить. Критерии API лучше, так как Java - ОО. Вот почему JPA создается. Когда JPQL скомпилирован, он будет преобразован в дерево AST (модель OO) перед переводом в SQL.

Солнечный день
источник
-3

HQL может вызвать проблемы безопасности, такие как SQL-инъекция.

Эмад Агайи
источник
11
Эти проблемы вызваны не HQL, а недостатком понимания основных практик разработки программного обеспечения. Я могу также создать код, подверженный атакам SQL-инъекций, с критериями api.
Йенс Шаудер
1
Это все равно, что сказать, что «запрос СУБД из Java может вызвать проблемы с безопасностью внедрения SQL»: D
Царь