JPA e Hibernate: criteri rispetto a JPQL o HQL


295

Quali sono i pro e i contro dell'utilizzo di Criteria o HQL ? L'API Criteria è un bel modo orientato agli oggetti per esprimere query in Hibernate, ma a volte le query Criteria sono più difficili da capire / costruire di HQL.

Quando usi i criteri e quando HQL? Cosa preferisci in quali casi d'uso? O è solo una questione di gusti?


La risposta giusta sarebbe "dipende dal caso d'uso".
Hace,

E questo strumento ? Permette di costruire query comuni in modo oggetto: clausola protetta 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
Definizione di una domanda basata sull'opinione pubblica, ma le persone non hanno colto l'occasione per chiuderla ... come da FAQ del sito

Risposte:


212

Preferisco principalmente le query dei criteri per le query dinamiche. Ad esempio, è molto più semplice aggiungere un po 'di ordinamento in modo dinamico o lasciare alcune parti (ad es. Restrizioni) a seconda di alcuni parametri.

D'altra parte sto usando HQL per query statiche e complesse, perché è molto più facile da capire / leggere HQL. Inoltre, penso che HQL sia un po 'più potente, ad esempio per diversi tipi di join.


13
Inoltre, sebbene Criteria appaia un po 'più sicuro per i tipi, l'unica cosa che può farti sentire al sicuro è il test.

Ci sono dei buoni esempi che mostrano perché l'HQL è migliore dei criteri API in alcuni casi? Ho letto la fine di un blog, ma non ho capito nulla. Lo apprezzerei se potessi aiutare. Grazie. Link - javalobby.org/articles/hibernatequery102
Erran Morad,

Tutte le ragioni sopra - preferisco anche Criteria a HQL perché è più sicuro per il programmatore, diminuendo gli errori di codifica - la compilazione sulla stringa HQL non è convalidata.
nuno,

Tuttavia, c'è il problema di recuperare entità distinte durante la paginazione. Facendo questo, sceglierei HQL per evitare problemi ...
Anthony Webster,

l'utilizzo della query dei criteri con un metamodello per i nomi delle colonne aiuta durante il refactoring a non rompere nulla e con un semplice comando di un IDE moderno per rinominare tutte le occorrenze nel codice.
Massimo

92

Esiste una differenza in termini di prestazioni tra HQL e criterioQuery, ogni volta che si attiva una query utilizzando criteriQuery, crea un nuovo alias per il nome della tabella che non si riflette nell'ultima cache interrogata per qualsiasi DB. Ciò comporta un sovraccarico di compilazione dell'SQL generato, impiegando più tempo per l'esecuzione.

Riguardo alle strategie di recupero [http://www.hibernate.org/315.html]

  • Criteri rispetta le impostazioni di pigrizia nei tuoi mapping e garantisce che venga caricato ciò che vuoi caricare. Ciò significa che una query Criteria potrebbe comportare diverse istruzioni SELECT immediate SQL per recuperare il sottografo con tutte le associazioni e le raccolte mappate non pigre. Se si desidera modificare il "come" e persino il "cosa", utilizzare setFetchMode () per abilitare o disabilitare il recupero del join esterno per una particolare raccolta o associazione. Le query sui criteri rispettano anche completamente la strategia di recupero (join vs select vs subselect).
  • HQL rispetta le impostazioni di pigrizia nei tuoi mapping e garantisce che venga caricato ciò che vuoi caricare. Ciò significa che una query HQL potrebbe comportare diverse istruzioni SELECT immediate SQL per recuperare il sottografo con tutte le associazioni e le raccolte mappate non pigre. Se si desidera modificare il "come" e anche il "cosa", utilizzare LEFT JOIN FETCH per abilitare il recupero del join esterno per una particolare raccolta o un'associazione molti-a-uno o uno-a-uno nullable o JOIN FETCH per abilitare recupero del join interno per un'associazione molti-a-uno o uno-a-uno non nullable. Le query HQL non rispettano alcun fetch = "join" definito nel documento di mapping.

1
Indico solo a chiunque stia navigando. che questa risposta è del 2008. questo potrebbe non essere più il caso. dimovelev.blogspot.com/2015/02/…
Amalgovinus,

41

Criteria è un'API orientata agli oggetti, mentre HQL significa concatenazione di stringhe. Ciò significa che si applicano tutti i vantaggi dell'orientamento agli oggetti:

  1. A parità di tutto il resto, la versione OO è leggermente meno soggetta a errori. Qualsiasi stringa precedente potrebbe essere aggiunta alla query HQL, mentre solo gli oggetti Criteria validi possono trasformarla in una struttura Criteria. In effetti, le classi Criteria sono più vincolate.
  2. Con il completamento automatico, OO è più rilevabile (e quindi più facile da usare, almeno per me). Non è necessario necessariamente ricordare quali parti della query vanno dove; l'IDE può aiutarti
  3. Inoltre, non è necessario ricordare i dettagli della sintassi (come i simboli dove vanno). Tutto quello che devi sapere è come chiamare metodi e creare oggetti.

Poiché HQL è molto simile a SQL (che la maggior parte degli sviluppatori conosce già molto bene), questi argomenti "non è necessario ricordare" non hanno lo stesso peso. Se HQL fosse più diverso, sarebbe più importante.


12
Questi argomenti non trattengono l'acqua (rispetto a HQL). Non deve comportare la concatenazione di stringhe. Che la versione OO sia meno soggetta a errori non è comprovata. È ugualmente soggetto a errori ma di diverso tipo. Lo sforzo di sapere quali metodi chiamare non è molto diverso dal sapere quali simboli chiamare in HQL (voglio dire, sul serio, non stiamo risolvendo PDE qui.)
luis.espinal

Ci sono dei buoni esempi che mostrano perché l'HQL è migliore dei criteri API in alcuni casi? Ho letto la fine di un blog, ma non ho capito nulla. Lo apprezzerei se potessi aiutare. Grazie. Link - javalobby.org/articles/hibernatequery102
Erran Morad

1
Le query denominate HQL vengono compilate al momento della distribuzione e a questo punto vengono rilevati i campi mancanti (forse per i refactor difettosi?). Penso che questo renda il codice più resistente e in effetti meno soggetto a errori rispetto ai criteri.
Narduk,

Il completamento automatico in Criteria è praticamente inutile perché le proprietà sono solo stringhe.
Lluis Martinez,

35

Di solito utilizzo i criteri quando non so quali input verranno utilizzati su quali dati. Come in un modulo di ricerca in cui l'utente può inserire da 1 a 50 voci e non so cosa cercheranno. È molto semplice aggiungere di più ai criteri mentre cerco ciò che l'utente sta cercando. Penso che sarebbe un po 'più problematico mettere una query HQL in quella circostanza. HQL è fantastico anche se so esattamente cosa voglio.


1
Questo è un bel commento Al momento costruiamo stringhe HQL molto grandi per un modulo di ricerca che contiene molti oggetti diversi attraverso i join. Sembra brutto. Andando a vedere se un criterio può ripulirlo. Interessante ...
cbmeeks

Grazie. Questo è un esempio eccellente. Potete per favore darmene ancora?
Erran Morad,

31

HQL è molto più facile da leggere, più facile da eseguire il debug utilizzando strumenti come il plugin Eclipse Hibernate e più facile da registrare. Le query con criteri sono migliori per la creazione di query dinamiche in cui gran parte del comportamento è determinato in fase di esecuzione. Se non conosci SQL, potrei capire usando le query Criteria, ma nel complesso preferisco HQL se so cosa voglio in anticipo.



21

Il criterio Api è uno dei buoni concetti di Hibernate. secondo me questi sono i pochi punti in cui possiamo fare la differenza tra HQL e Criteria Api

  1. HQL deve eseguire operazioni di selezione e non selezione sui dati, ma i criteri sono solo per la selezione dei dati, non è possibile eseguire operazioni di non selezione utilizzando i criteri.
  2. HQL è adatto per l'esecuzione di query statiche, mentre come criterio è adatto per l'esecuzione di query dinamiche
  3. HQL non supporta il concetto di impaginazione , ma possiamo ottenere l'impaginazione con i criteri.
  4. I criteri impiegavano più tempo per l'esecuzione rispetto a HQL.
  5. Con Criteria siamo al sicuro con SQL Injection a causa della sua generazione dinamica di query ma in HQL poiché le tue query sono fisse o parametrizzate, non c'è sicurezza da SQL Injection

11
Un paio di punti La paginazione è presente in HQL: puoi usare limit offset:rows In hql puoi evitare l'iniezione sql usandosetParameter
Viswanath Lekshmanan

13

Per utilizzare il meglio dei due mondi, l'espressività e la concisione di HQL e la natura dinamica dei Criteri considerano l'uso di Querydsl .

Querydsl supporta JPA / Hibernate, JDO, SQL e Collections.

Sono il manutentore di Querydsl, quindi questa risposta è parziale.


13

Per me Criteria è abbastanza facile da capire e fare query dinamiche. Ma il difetto che dico finora è che carica tutte le relazioni di molti uno ecc. Perché abbiamo solo tre tipi di FetchModes cioè Select, Proxy e Default e in tutti questi casi carica molti uno (potrebbe essere sbagliato se così aiuto me fuori :))

Il secondo problema con Criteria è che carica un oggetto completo, ad esempio se voglio solo caricare EmpName di un dipendente, non verrà fornito con questo istante, verrà fornito con l'oggetto Employee completo e posso ottenere EmpName da esso, perché funziona davvero male in segnalazione . dove come HQL ha appena caricato (non ha caricato associazione / relazioni) ciò che si desidera così aumentare le prestazioni molte volte.

Una caratteristica di Criteria è che ti proteggerà da SQL Injection a causa della sua generazione dinamica di query in cui, come in HQL, le tue query sono fisse o parametrizzate, quindi non sono sicure da SQL Injection.

Inoltre, se scrivi HQL nei tuoi file aspx.cs, sei strettamente associato al tuo DAL.

Nel complesso la mia conclusione è che ci sono posti in cui non puoi vivere senza HQL come i rapporti, quindi usali altrimenti I criteri sono più facili da gestire.


13
HQL NON è sicuro per l'iniezione di SQL
Varun Mehta,

Penso che i criteri non siano sicuri per l'iniezione. Vedi il mio post qui: stackoverflow.com/questions/6746486/…
Mister Smith,

4
HQL IS sql injection safe aggiungendo 'setParameter'
Javatar

2
@Zafar: puoi selezionare solo alcune proprietà di un'entità usando le proiezioni
Răzvan Flavius ​​Panda

@Zafar è possibile impostare la proiezione nella query dei criteri per selezionare colonne particolari. Puoi recuperare EmpName, non è necessario recuperare l'oggetto completo.
Khatri,

12

API dei criteri

L'API dei criteri è più adatta per le query generate dinamicamente. Pertanto, se si desidera aggiungere filtri della clausola WHERE, clausole JOIN o variare la clausola ORDER BY o le colonne di proiezione, l'API Criteria può aiutarti a generare la query in modo dinamico in modo da prevenire anche attacchi SQL Injection .

D'altra parte, le query sui criteri sono meno espressive e possono persino portare a query SQL molto complicate e inefficienti, come spiegato in questo articolo .

JPQL e HQL

JPQL è il linguaggio di query dell'entità standard JPA mentre HQL estende JPQL e aggiunge alcune funzionalità specifiche di Hibernate.

JPQL e HQL sono molto espressivi e assomigliano a SQL. A differenza dell'API Criteria, JPQL e HQL semplificano la previsione della query SQL sottostante generata dal provider JPA. È anche molto più facile rivedere le proprie query HQL rispetto a quelle di Criteria.

Vale la pena notare che la selezione di entità con JPQL o API Criteria ha senso se è necessario modificarle. Altrimenti, una proiezione DTO è una scelta molto migliore.

Conclusione

Se non è necessario variare la struttura della query dell'entità, utilizzare JPQL o HQL. Se è necessario modificare i criteri di filtro o di ordinamento o modificare la proiezione, utilizzare l'API Criteria.

Tuttavia, solo perché stai usando JPA o Hibernate, ciò non significa che non dovresti usare SQL nativo. Le query SQL sono molto utili e le API JPQL e Criteria non sostituiscono SQL. Consulta questo articolo per maggiori dettagli su questo argomento.



11

Per me la più grande vittoria su Criteria è l'API di esempio, in cui è possibile passare un oggetto e l'ibernazione costruirà una query basata su quelle proprietà dell'oggetto.

Oltre a ciò, i criteri API hanno le sue stranezze (credo che il team di ibernazione stia rielaborando l'API), come:

  • a criterio.createAlias ​​("obj") forza un join interno anziché un possibile join esterno
  • non puoi creare lo stesso alias due volte
  • alcune clausole sql non hanno una controparte con criteri semplici (come una sottoselezione)
  • eccetera.

Tendo a utilizzare HQL quando voglio query simili a sql (elimina da Utenti dove status = 'bloccato') e tendo a utilizzare i criteri quando non desidero utilizzare l'aggiunta di stringhe.

Un altro vantaggio di HQL è che puoi definire tutte le tue domande in anticipo e persino esternalizzarle in un file o giù di lì.


9

I criteri api forniscono una caratteristica distinta che né SQL né HQL forniscono. vale a dire. consente il controllo del tempo di compilazione di una query.


7

Abbiamo utilizzato principalmente Criteri nella nostra applicazione all'inizio, ma dopo che è stato sostituito con HQL a causa di problemi di prestazioni.
Principalmente stiamo usando query molto complesse con diversi join che portano a più query in Criteria ma sono molto ottimizzate in HQL.
Il caso è che usiamo solo diverse proprietà su oggetti specifici e non su oggetti completi. Con Criteria il problema era anche la concatenazione di stringhe.
Diciamo che se hai bisogno di visualizzare il nome e il cognome dell'utente in HQL è abbastanza facile (name || ' ' || surname)ma in Crteria questo non è possibile.
Per ovviare a questo problema abbiamo usato i risultatiTransormer, dove c'erano metodi in cui tale concatenazione era implementata per il risultato necessario.
Oggi usiamo principalmente HQL in questo modo:

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

quindi nel nostro caso i record restituiti sono mappe delle proprietà necessarie.


1
Con Criteria puoi usare org.hibernate.criterion.CriteriaSpecification.ALIAS_TO_ENTITY_MAP
AA.

La restituzione di un elenco di mappe nella mia esperienza ha una performance pessima. Preferisco restituire un elenco di matrici di oggetti o un elenco di bean (è sempre possibile definire un bean adatto al proprio set di risultati specifico).
Lluis Martinez,

7
  • HQL deve eseguire operazioni di selezione e non selezione sui dati, ma i criteri sono solo per la selezione dei dati, non possiamo eseguire operazioni di non selezione utilizzando i criteri
  • HQL è adatto per l'esecuzione di query statiche, mentre come criterio è adatto per l'esecuzione di query dinamiche
  • HQL non supporta il concetto di impaginazione, ma possiamo ottenere l'impaginazione con i criteri
  • I criteri impiegavano più tempo per l'esecuzione di HQL
  • Con Criteria siamo al sicuro con SQL Injection grazie alla sua generazione dinamica di query ma in HQL poiché le tue query sono fisse o parametrizzate, non c'è sicurezza da SQL Injection.

fonte


Per chiarire, le query sui criteri che utilizzano l'API dei criteri di Hibernate possono essere disponibili per le query, ma le query sui criteri JPA coprono selezioni, aggiornamenti ed eliminazioni. Vedi CriteriaUpdate<T>e CriteriaDelete<T>per riferimento.
Naros,

5

Criteri di query per dinamicamente possiamo costruire query in base ai nostri input .. Nel caso di query Hql è la query statica una volta che abbiamo costruito non possiamo cambiare la struttura della query.


2
Non così. Con HQL è possibile impostare le proprietà con l'identificatore ':', quindi sostituire quelle proprietà con valori univoci. Ad esempio, Query q = session.createQuery ("SELECT: aValue FROM my_table"); e quindi q.setParameter ("aValue", "some_column_name");
MattC

@MattC Nel tuo esempio stai cambiando i valori dei parametri, non la struttura della query.
Zar,

4

Non voglio calciare un cavallo morto qui, ma è importante menzionare che le query dei criteri ora sono deprecate. Usa HQL.


1

Preferisco anche le query dei criteri per le query dinamiche. Ma preferisco hql per le query di eliminazione, ad esempio se elimina tutti i record dalla tabella figlio per l'id parent 'xyz', è facilmente raggiungibile da HQL, ma per i criteri API prima dobbiamo attivare n numero di query di eliminazione dove n è il numero di child record di tabella.


0

La maggior parte delle risposte qui sono fuorvianti e menzionano che Criteria Queriessono più lente di HQL, il che in realtà non è il caso.

Se approfondisci ed esegui alcuni test, vedrai che le query dei criteri funzionano molto meglio del normale HQL .

E anche con Criteria Query ottieni un controllo orientato agli oggetti che non è presente con HQL .

Per maggiori informazioni leggi questa risposta qui .


0

C'è un altro modo. Ho finito con la creazione di un parser HQL basato sulla sintassi originale in ibernazione, in modo che prima analizzasse l'HQL, quindi potesse iniettare dinamicamente parametri dinamici o aggiungere automaticamente alcuni filtri comuni per le query HQL. Funziona benissimo!


0

Questo post è piuttosto vecchio. La maggior parte delle risposte parla di criteri di ibernazione, non di criteri JPA. JPA 2.1 ha aggiunto CriteriaDelete / CriteriaUpdate e EntityGraph che controlla esattamente cosa recuperare. L'API dei criteri è migliore poiché Java è OO. Ecco perché viene creato l'APP. Quando viene compilato, JPQL verrà tradotto in albero AST (modello OO) prima di essere tradotto in SQL.


-3

HQL può causare problemi di sicurezza come l'iniezione SQL.


11
Questi problemi non sono causati da HQL, ma dalla mancanza di comprensione delle pratiche di sviluppo del software di base. Posso creare codice incline agli attacchi di iniezione sql anche con criteri api.
Jens Schauder,

1
È come dire "interrogare un RDBMS da Java può causare problemi di sicurezza nell'iniezione SQL": D
Zar
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.