JPA und Hibernate - Kriterien vs. JPQL oder HQL

295

Was sind die Vor- und Nachteile der Verwendung von Kriterien oder HQL ? Die Kriterien-API ist eine nette objektorientierte Methode, um Abfragen im Ruhezustand auszudrücken. Manchmal sind Kriterienabfragen jedoch schwieriger zu verstehen / zu erstellen als HQL.

Wann verwenden Sie Kriterien und wann HQL? Was bevorzugen Sie in welchen Anwendungsfällen? Oder ist es nur Geschmackssache?

Cretzel
quelle
Die richtige Antwort wäre "hängt vom Anwendungsfall ab".
Hace
Und was ist mit diesem Tool ? Es ermöglicht das Erstellen allgemeiner Abfragen auf objektweise Weise: protected Clause 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 (); }
Vojtěch
1
Definition einer meinungsbasierten Frage, aber die Leute haben die Gelegenheit nicht genutzt, um sie zu schließen ... gemäß der FAQ der Site

Antworten:

212

Ich bevorzuge hauptsächlich Kriterienabfragen für dynamische Abfragen. Zum Beispiel ist es viel einfacher, eine Reihenfolge dynamisch hinzuzufügen oder einige Teile (z. B. Einschränkungen) abhängig von bestimmten Parametern wegzulassen.

Andererseits verwende ich HQL für statische und komplexe Abfragen, weil es viel einfacher ist, HQL zu verstehen / zu lesen. Außerdem ist HQL meiner Meinung nach etwas leistungsfähiger, z. B. für verschiedene Join-Typen.

Cretzel
quelle
13
Auch wenn Kriterien etwas typsicherer aussehen, können Sie sich nur durch Testen sicher fühlen.
Gibt es gute Beispiele, die zeigen, warum HQL in bestimmten Fällen besser ist als Kriterien-API? Ich habe das Ende eines Blogs gelesen, aber nichts verstanden. Würde mich freuen, wenn Sie helfen könnten. Vielen Dank. Link - javalobby.org/articles/hibernatequery102
Erran Morad
Alle oben genannten Gründe - Ich bevorzuge auch Kriterien gegenüber HQL, da dies für den Programmierer sicherer ist und Codierungsfehler verringert - die Kompilierung der HQL-Zeichenfolge wird nicht validiert.
Nuno
Es gibt jedoch das Problem, bestimmte Entitäten während der Paginierung abzurufen. Wenn ich das mache, würde ich HQL wählen, um Probleme zu vermeiden ...
Anthony Webster
Die Verwendung der Kriterienabfrage mit einem Metamodell für die Spaltennamen hilft beim Refactoring, nichts zu beschädigen, und mit einem einfachen Befehl einer modernen IDE, alle Vorkommen im Code umzubenennen.
Massimo
92

Es gibt einen Leistungsunterschied zwischen HQL und KriterienQuery. Jedes Mal, wenn Sie eine Abfrage mit KriterienQuery auslösen, wird ein neuer Alias ​​für den Tabellennamen erstellt, der im zuletzt abgefragten Cache für eine Datenbank nicht berücksichtigt wird. Dies führt zu einem Overhead beim Kompilieren des generierten SQL, dessen Ausführung mehr Zeit in Anspruch nimmt.

In Bezug auf Abrufstrategien [http://www.hibernate.org/315.html]

  • Kriterien berücksichtigen die Faulheitseinstellungen in Ihren Zuordnungen und garantieren, dass das, was Sie laden möchten, geladen wird. Dies bedeutet, dass eine Kriterienabfrage möglicherweise zu mehreren sofortigen SQL-SELECT-Anweisungen führt, um den Untergraphen mit allen nicht verzögerten zugeordneten Zuordnungen und Sammlungen abzurufen. Wenn Sie das "Wie" und sogar das "Was" ändern möchten, verwenden Sie setFetchMode (), um das Abrufen äußerer Verknüpfungen für eine bestimmte Sammlung oder Zuordnung zu aktivieren oder zu deaktivieren. Kriterienabfragen berücksichtigen auch vollständig die Abrufstrategie (Join vs Select vs Subselect).
  • HQL respektiert die Faulheitseinstellungen in Ihren Zuordnungen und garantiert, dass das, was Sie laden möchten, geladen wird. Dies bedeutet, dass eine HQL-Abfrage möglicherweise zu mehreren SQL-Sofort-SELECT-Anweisungen führt, um den Untergraphen mit allen nicht verzögerten zugeordneten Zuordnungen und Sammlungen abzurufen. Wenn Sie das "Wie" und sogar das "Was" ändern möchten, verwenden Sie LEFT JOIN FETCH, um das Abrufen von Outer-Joins für eine bestimmte Sammlung oder nullbare Viele-zu-Eins- oder Eins-zu-Eins-Zuordnungen zu aktivieren, oder JOIN FETCH, um dies zu aktivieren Abrufen der inneren Verknüpfung für eine nicht nullfähige Viele-zu-Eins- oder Eins-zu-Eins-Zuordnung. HQL-Abfragen berücksichtigen keine im Mapping-Dokument definierten fetch = "join".
Varun Mehta
quelle
1
Ich möchte nur darauf hinweisen, dass jemand surft. dass diese Antwort aus dem Jahr 2008 stammt. Dies ist möglicherweise nicht mehr der Fall. dimovelev.blogspot.com/2015/02/…
Amalgovinus
41

Criteria ist eine objektorientierte API, während HQL die Verkettung von Zeichenfolgen bedeutet. Das heißt, alle Vorteile der Objektorientierung gelten:

  1. Wenn alles andere gleich ist, ist die OO-Version etwas weniger fehleranfällig. Jede alte Zeichenfolge kann an die HQL-Abfrage angehängt werden, während nur gültige Kriterienobjekte in einen Kriterienbaum aufgenommen werden können. Tatsächlich sind die Kriterienklassen eingeschränkter.
  2. Mit der automatischen Vervollständigung ist das OO besser erkennbar (und damit zumindest für mich einfacher zu bedienen). Sie müssen sich nicht unbedingt merken, welche Teile der Abfrage wohin gehen. Die IDE kann Ihnen helfen
  3. Sie müssen sich auch nicht an die Einzelheiten der Syntax erinnern (z. B. welche Symbole wohin gehen). Sie müssen lediglich wissen, wie Sie Methoden aufrufen und Objekte erstellen.

Da HQL SQL sehr ähnlich ist (was die meisten Entwickler bereits sehr gut kennen), haben diese Argumente, an die man sich nicht erinnern muss, nicht so viel Gewicht. Wenn HQL anders wäre, wäre dies wichtiger.

Craig Walker
quelle
12
Diese Argumente enthalten kein Wasser (in Bezug auf HQL). Es muss keine Verkettung von Zeichenfolgen erforderlich sein. Dass die OO-Version weniger fehleranfällig ist, ist unbegründet. Es ist gleichermaßen fehleranfällig, aber von anderer Art. Die Anstrengung zu wissen, welche Methoden aufgerufen werden sollen, unterscheidet sich nicht wesentlich von der Anstrengung, zu wissen, welche Symbole in HQL aufgerufen werden sollen (ich meine, im Ernst, wir lösen hier keine PDEs.)
luis.espinal
Gibt es gute Beispiele, die zeigen, warum HQL in bestimmten Fällen besser ist als Kriterien-API? Ich habe das Ende eines Blogs gelesen, aber nichts verstanden. Würde mich freuen, wenn Sie helfen könnten. Vielen Dank. Link - javalobby.org/articles/hibernatequery102
Erran Morad
1
Abfragen mit HQL-Namen werden zur Bereitstellungszeit kompiliert und zu diesem Zeitpunkt werden fehlende Felder (möglicherweise für fehlerhafte Refaktoren?) Erkannt. Ich denke, dies macht Code widerstandsfähiger und in der Tat weniger fehleranfällig als Kriterien.
Narduk
Die automatische Vervollständigung in Kriterien ist so gut wie nutzlos, da die Eigenschaften nur Zeichenfolgen sind.
Lluis Martinez
35

Normalerweise verwende ich Kriterien, wenn ich nicht weiß, welche Eingaben für welche Daten verwendet werden. Wie bei einem Suchformular, bei dem der Benutzer 1 bis 50 Elemente eingeben kann und ich nicht weiß, wonach er suchen wird. Es ist sehr einfach, mehr an die Kriterien anzuhängen, während ich überprüfe, wonach der Benutzer sucht. Ich denke, es wäre etwas schwieriger, unter diesen Umständen eine HQL-Abfrage zu stellen. HQL ist großartig, wenn ich genau weiß, was ich will.

Arthur Thomas
quelle
1
Dies ist ein guter Kommentar. Wir erstellen derzeit sehr große HQL-Zeichenfolgen für ein Suchformular, das über Joins viele verschiedene Objekte enthält. Sieht hässlich aus. Ich werde sehen, ob ein Kriterium das bereinigen kann. Interessant ...
cbmeeks
Vielen Dank. Dies ist ein hervorragendes Beispiel. Können Sie mir bitte noch etwas geben?
Erran Morad
31

HQL ist viel einfacher zu lesen, mit Tools wie dem Eclipse Hibernate-Plugin einfacher zu debuggen und einfacher zu protokollieren. Kriterienabfragen eignen sich besser zum Erstellen dynamischer Abfragen, bei denen ein Großteil des Verhaltens zur Laufzeit bestimmt wird. Wenn Sie SQL nicht kennen, könnte ich die Verwendung von Kriterienabfragen verstehen, aber insgesamt bevorzuge ich HQL, wenn ich weiß, was ich im Voraus möchte.

Brian Deterling
quelle
22

Kriterien sind die einzige Möglichkeit, natürliche Schlüsselsuchen anzugeben, die die spezielle Optimierung im Abfragecache der zweiten Ebene nutzen. HQL hat keine Möglichkeit, den erforderlichen Hinweis anzugeben.

Weitere Informationen finden Sie hier:

Alex Miller
quelle
21

Kriterien Api ist eines der guten Konzepte von Hibernate. Meiner Ansicht nach sind dies die wenigen Punkte, anhand derer wir zwischen HQL und Criteria Api unterscheiden können

  1. HQL soll sowohl Auswahl- als auch Nichtauswahloperationen für die Daten ausführen. Kriterien dienen jedoch nur zur Auswahl der Daten. Wir können keine Nichtauswahloperationen unter Verwendung von Kriterien ausführen.
  2. HQL eignet sich zum Ausführen statischer Abfragen, während als Kriterien zum Ausführen dynamischer Abfragen geeignet ist
  3. HQL unterstützt das Paginierungskonzept nicht , aber wir können die Paginierung mit Kriterien erreichen.
  4. Die Ausführung von Kriterien dauerte früher länger als bei HQL.
  5. Mit Criteria sind wir mit SQL Injection aufgrund seiner dynamischen Abfragegenerierung sicher, aber in HQL gibt es keinen Safe vor SQL Injection, da Ihre Abfragen entweder fest oder parametrisiert sind
Arvind
quelle
11
limit offset:rows Einige Punkte Paginierung gibt es in HQL: Sie können verwenden In HQL können Sie SQL-Injektion mitsetParameter
Viswanath Lekshmanan
13

Um das Beste aus beiden Welten zu nutzen, sollten Querydsl , die Expressivität und Prägnanz von HQL sowie die Dynamik von Kriterien in Betracht gezogen werden .

Querydsl unterstützt JPA / Hibernate, JDO, SQL und Collections.

Ich bin der Betreuer von Querydsl, daher ist diese Antwort voreingenommen.

Timo Westkämper
quelle
13

Für mich ist Criteria ein ziemlich leicht zu verstehendes und dynamisches Abfragen. Aber der Fehler, den ich bisher sage, ist, dass es alle Beziehungen mit vielen Einsen usw. lädt, weil wir nur drei Arten von FetchModes haben, nämlich Select, Proxy und Default, und in all diesen Fällen lädt er viele Einsen (möglicherweise irre ich mich, wenn dies hilft mich raus :))

Das zweite Problem mit Criteria ist, dass es ein vollständiges Objekt lädt. Wenn ich also nur EmpName eines Mitarbeiters laden möchte, wird es nicht mit diesem Instant angezeigt. Es wird ein vollständiges Employee-Objekt erstellt, und ich kann EmpName daraus abrufen, da es wirklich schlecht funktioniert Berichterstattung . Wo als HQL nur geladen wurde (Assoziationen / Relationen wurden nicht geladen), was Sie wollen, erhöhen Sie die Leistung um ein Vielfaches.

Ein Merkmal von Criteria ist, dass es Sie aufgrund seiner dynamischen Abfragegenerierung vor SQL Injection schützt, wobei wie in HQL Ihre Abfragen entweder fest oder parametrisiert sind und daher nicht vor SQL Injection sicher sind.

Auch wenn Sie HQL in ur aspx.cs-Dateien schreiben, sind Sie eng mit ur DAL verbunden.

Insgesamt bin ich zu dem Schluss gekommen, dass es Orte gibt, an denen Sie ohne HQL-ähnliche Berichte nicht leben können. Verwenden Sie sie daher, sonst sind die Kriterien einfacher zu verwalten.

Zafar
quelle
13
HQL ist NICHT SQL Injection Safe
Varun Mehta
Ich denke, Kriterien sind nicht spritzwassergeschützt. Siehe meinen Beitrag hier: stackoverflow.com/questions/6746486/…
Mister Smith
4
HQL ist SQL Injection Safe durch Hinzufügen von 'setParameter'
Javatar
2
@ Zafar: Sie können nur bestimmte Eigenschaften einer Entität mithilfe von Projektionen auswählen
Răzvan Flavius ​​Panda
@Zafar Sie können die Projektion in der Kriterienabfrage festlegen, um bestimmte Spalten auszuwählen. Sie können EmpName abrufen, ohne das vollständige Objekt abrufen zu müssen.
Khatri
12

Kriterien-API

Die Kriterien-API eignet sich besser für dynamisch generierte Abfragen. Wenn Sie also WHERE-Klauselfilter, JOIN-Klauseln oder die ORDER BY-Klausel oder die Projektionsspalten hinzufügen möchten, kann Ihnen die Kriterien-API dabei helfen, die Abfrage dynamisch so zu generieren, dass auch SQL Injection-Angriffe verhindert werden .

Auf der anderen Seite sind Kriterienabfragen weniger aussagekräftig und können sogar zu sehr komplizierten und ineffizienten SQL-Abfragen führen, wie in diesem Artikel erläutert .

JPQL und HQL

JPQL ist die Abfragesprache für JPA-Standardentitäten, während HQL JPQL erweitert und einige Hibernate-spezifische Funktionen hinzufügt.

JPQL und HQL sind sehr ausdrucksstark und ähneln SQL. Im Gegensatz zur Criteria API erleichtern JPQL und HQL die Vorhersage der zugrunde liegenden SQL-Abfrage, die vom JPA-Anbieter generiert wird. Es ist auch viel einfacher, die eigenen HQL-Abfragen zu überprüfen als die Kriterien.

Es ist erwähnenswert, dass die Auswahl von Entitäten mit JPQL- oder Kriterien-API sinnvoll ist, wenn Sie sie ändern müssen. Ansonsten ist eine DTO-Projektion eine viel bessere Wahl.

Fazit

Wenn Sie die Struktur der Entitätsabfrage nicht ändern müssen, verwenden Sie JPQL oder HQL. Wenn Sie die Filter- oder Sortierkriterien oder die Projektion ändern müssen, verwenden Sie die Kriterien-API.

Nur weil Sie JPA oder Hibernate verwenden, bedeutet dies nicht, dass Sie kein natives SQL verwenden sollten. SQL-Abfragen sind sehr nützlich und JPQL und die Kriterien-API sind kein Ersatz für SQL. In diesem Artikel finden Sie weitere Informationen zu diesem Thema.

Vlad Mihalcea
quelle
11

Für mich ist der größte Gewinn bei Criteria die Beispiel-API, bei der Sie ein Objekt übergeben können und der Ruhezustand eine Abfrage basierend auf diesen Objekteigenschaften erstellt.

Abgesehen davon hat die Kriterien-API ihre Macken (ich glaube, das Hibernate-Team überarbeitet die API) wie:

  • Ein Kriterien.createAlias ​​("obj") erzwingt einen inneren Join anstelle eines möglichen äußeren Joins
  • Sie können nicht zweimal denselben Alias ​​erstellen
  • Einige SQL-Klauseln haben kein einfaches Kriterium (wie eine Unterauswahl).
  • etc.

Ich verwende normalerweise HQL, wenn ich Abfragen ähnlich wie SQL möchte (Löschen von Benutzern, bei denen status = 'blockiert'), und ich verwende Kriterien, wenn ich kein Anhängen von Zeichenfolgen verwenden möchte.

Ein weiterer Vorteil von HQL ist, dass Sie alle Ihre Abfragen vorab definieren und sogar in eine Datei oder so auslagern können.

Miguel Ping
quelle
9

Criteria API bietet eine bestimmte Funktion, die weder SQL noch HQL bieten. dh. Es ermöglicht die Überprüfung der Kompilierungszeit einer Abfrage.

user1165443
quelle
7

Am Anfang haben wir in unserer Anwendung hauptsächlich Kriterien verwendet, aber nachdem sie aufgrund von Leistungsproblemen durch HQL ersetzt wurde.
Hauptsächlich verwenden wir sehr komplexe Abfragen mit mehreren Verknüpfungen, was zu mehreren Abfragen in Kriterien führt, aber in HQL sehr optimiert ist.
Der Fall ist, dass wir nur einige Eigenschaften für ein bestimmtes Objekt verwenden und keine vollständigen Objekte. Bei Criteria war das Problem auch die Verkettung von Zeichenfolgen.
Angenommen, Sie müssen den (name || ' ' || surname)Vor- und Nachnamen des Benutzers in HQL anzeigen, dies ist recht einfach , in Crteria ist dies jedoch nicht möglich.
Um dies zu überwinden, verwendeten wir ResultTransormers, bei denen es Methoden gab, bei denen eine solche Verkettung für das erforderliche Ergebnis implementiert wurde.
Heute verwenden wir hauptsächlich HQL wie folgt:

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

In unserem Fall handelt es sich bei den zurückgegebenen Datensätzen also um Karten der benötigten Eigenschaften.

Bojan Kraut
quelle
1
Mit Criteria können Sie org.hibernate.criterion.CriteriaSpecification.ALIAS_TO_ENTITY_MAP
AA verwenden.
Das Zurückgeben einer Liste von Karten hat meiner Erfahrung nach eine sehr schlechte Leistung. Ich bevorzuge es, eine Liste von Objektarrays oder eine Liste von Beans zurückzugeben (Sie können immer eine Bean definieren, die zu Ihrer spezifischen Ergebnismenge passt).
Lluis Martinez
7
  • HQL soll sowohl Auswahl- als auch Nichtauswahloperationen für die Daten ausführen. Kriterien dienen jedoch nur zur Auswahl der Daten. Wir können keine Nichtauswahloperationen unter Verwendung von Kriterien ausführen
  • HQL eignet sich zum Ausführen statischer Abfragen, während als Kriterien zum Ausführen dynamischer Abfragen geeignet ist
  • HQL unterstützt das Paginierungskonzept nicht, aber wir können die Paginierung mit Kriterien erreichen
  • Die Ausführung von Kriterien dauerte früher länger als bei HQL
  • Mit Criteria sind wir mit SQL Injection aufgrund seiner dynamischen Abfragegenerierung sicher, aber in HQL gibt es keinen Safe vor SQL Injection, da Ihre Abfragen entweder fest oder parametrisiert sind.

Quelle

Premraj
quelle
Zur Verdeutlichung stehen Kriterienabfragen mithilfe der Kriterien-API von Hibernate möglicherweise zum Abfragen zur Verfügung. JPA-Kriterienabfragen umfassen jedoch Auswahlen, Aktualisierungen und Löschungen. Siehe CriteriaUpdate<T>und CriteriaDelete<T>als Referenz.
Naros
5

Kriterienabfrage für dynamisch können wir eine Abfrage basierend auf unseren Eingaben erstellen. Im Fall einer Hql-Abfrage ist die statische Abfrage, sobald wir sie erstellt haben, können wir die Struktur der Abfrage nicht ändern.

user1679378
quelle
2
Nicht so. Mit HQL können Sie Eigenschaften mit dem Bezeichner ':' festlegen und diese Eigenschaften dann durch eindeutige Werte ersetzen. Beispiel: Abfrage q = session.createQuery ("SELECT: aValue FROM my_table"); und dann q.setParameter ("aValue", "some_column_name");
MattC
@MattC In Ihrem Beispiel ändern Sie die Werte der Parameter, nicht die Struktur der Abfrage.
Zar
4

Ich möchte hier kein totes Pferd treten, aber es ist wichtig zu erwähnen, dass Kriterienabfragen jetzt veraltet sind. Verwenden Sie HQL.

Eskir
quelle
1

Ich bevorzuge auch Kriterienabfragen für dynamische Abfragen. Aber ich bevorzuge hql zum Löschen von Abfragen, zum Beispiel, wenn alle Datensätze aus der untergeordneten Tabelle für die übergeordnete ID 'xyz' gelöscht werden. Dies wird von HQL leicht erreicht, aber für die Kriterien-API müssen wir zuerst n Anzahl der Löschabfragen auslösen, wobei n die Anzahl der untergeordneten Abfragen ist Tabellendatensätze.

Punit Patel
quelle
0

Die meisten Antworten hier sind irreführend und erwähnen, dass sie Criteria Querieslangsamer sind als HQL, was eigentlich nicht der Fall ist.

Wenn Sie tief eintauchen und einige Tests durchführen, werden Sie feststellen, dass Kriterienabfragen viel besser abschneiden als reguläres HQL .

Und auch mit Criteria Query erhalten Sie eine objektorientierte Steuerung, die mit HQL nicht vorhanden ist .

Für weitere Informationen lesen Sie diese Antwort hier .

Pritam Banerjee
quelle
0

Es geht auch anders. Am Ende habe ich einen HQL-Parser erstellt, der auf der ursprünglichen Syntax im Ruhezustand basiert, sodass zuerst der HQL analysiert und dann dynamische Parameter dynamisch eingefügt oder automatisch einige allgemeine Filter für die HQL-Abfragen hinzugefügt werden können. Es funktioniert super!

Wallace Peng
quelle
0

Dieser Beitrag ist ziemlich alt. Die meisten Antworten beziehen sich auf Ruhezustandskriterien, nicht auf JPA-Kriterien. JPA 2.1 fügte CriteriaDelete / CriteriaUpdate und EntityGraph hinzu, die steuern, was genau abgerufen werden soll. Die Kriterien-API ist besser, da Java OO ist. Deshalb wird JPA erstellt. Wenn JPQL kompiliert wird, wird es in den AST-Baum (OO-Modell) übersetzt, bevor es in SQL übersetzt wird.

Sonniger Tag
quelle
-3

HQL kann Sicherheitsbedenken wie SQL-Injection verursachen.

Emad Aghayi
quelle
11
Diese Probleme werden nicht durch HQL verursacht, sondern durch das mangelnde Verständnis grundlegender Softwareentwicklungspraktiken. Ich kann Code erstellen, der für SQL-Injection-Angriffe mit Kriterien-API anfällig ist.
Jens Schauder
1
Es ist wie zu sagen, "das Abfragen eines RDBMS von Java kann Sicherheitsbedenken hinsichtlich der SQL-Injektion verursachen": D
Czar