JPA i Hibernacja - kryteria kontra JPQL lub HQL

295

Jakie są zalety i wady korzystania z Criteria lub HQL ? Criteria API to przyjemny obiektowo sposób wyrażania zapytań w Hibernacji, ale czasami zapytania Criteria są trudniejsze do zrozumienia / zbudowania niż HQL.

Kiedy korzystasz z kryteriów, a kiedy HQL? Co wolisz w jakich przypadkach użycia? Czy to tylko kwestia gustu?

Kretyn
źródło
Prawidłowa odpowiedź brzmi „zależy od przypadku użycia”.
Hace
A co z tym narzędziem ? Umożliwia konstruowanie typowych zapytań w sposób obiektowy: chroniona klauzula 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 =?", ślimak) .fetchSingle (); }
Vojtěch
1
Definicja pytania opartego na opiniach, ale ludzie nie skorzystali z okazji, aby je zamknąć ... zgodnie z FAQ witryny

Odpowiedzi:

212

Najbardziej preferuję zapytania kryteriów dla zapytań dynamicznych. Na przykład znacznie łatwiej jest dynamicznie dodawać niektóre zamówienia lub pomijać niektóre części (np. Ograniczenia) w zależności od parametru.

Z drugiej strony używam HQL do zapytań statycznych i złożonych, ponieważ dużo łatwiej jest zrozumieć / odczytać HQL. Poza tym HQL jest nieco mocniejszy, jak sądzę, np. Dla różnych typów złączeń.

Kretyn
źródło
13
Ponadto, chociaż kryteria wydają się bardziej bezpieczne dla typu, jedyne, co może sprawić, że poczujesz się bezpiecznie, to testy.
Czy są jakieś dobre przykłady, które pokazują, dlaczego HQL jest lepszy niż kryteria API w niektórych przypadkach? Przeczytałem koniec jednego bloga, ale nic nie zrozumiałem. Byłbym wdzięczny, gdybyś mógł pomóc. Dzięki. Link - javalobby.org/articles/hibernatequery102
Erran Morad
Wszystkie powyższe powody - ja też wolę Kryteria niż HQL, ponieważ jest to bezpieczniejsze dla programisty, zmniejsza błędy kodowania - kompilacja na łańcuchu HQL nie jest sprawdzana.
Nuno
Istnieje jednak problem pobierania różnych jednostek podczas paginacji. Robiąc to, wybrałem HQL, aby uniknąć problemów ...
Anthony Webster,
użycie zapytania kryteriów z metamodelem dla nazw kolumn pomaga podczas refaktoryzacji niczego nie zepsuć i za pomocą prostej komendy ze współczesnego IDE, aby zmienić nazwę wszystkich wystąpień w kodzie.
Massimo,
92

Istnieje różnica pod względem wydajności między HQL a kryterium Zapytanie. Za każdym razem, gdy uruchamiasz zapytanie za pomocą kryterium Zapytanie, tworzy on nowy alias dla nazwy tabeli, który nie ma odzwierciedlenia w pamięci podręcznej ostatniego zapytania dla dowolnej bazy danych. Prowadzi to do narzutu związanego z kompilacją wygenerowanego kodu SQL, co zajmuje więcej czasu.

Odnośnie strategii pobierania [http://www.hibernate.org/315.html]

  • Kryteria uwzględniają ustawienia lenistwa w twoich mapowaniach i gwarantują, że załadowane zostanie to, co chcesz załadować. Oznacza to, że jedno zapytanie Criteria może skutkować kilkoma instrukcjami SQL typu SELECT natychmiastowymi do pobrania subgrafu ze wszystkimi nieludzkimi mapowanymi powiązaniami i kolekcjami. Jeśli chcesz zmienić „jak”, a nawet „co”, użyj setFetchMode (), aby włączyć lub wyłączyć pobieranie złączeń zewnętrznych dla określonej kolekcji lub powiązania. Zapytania dotyczące kryteriów również w pełni respektują strategię pobierania (łączenie vs wybór kontra podselekcja).
  • HQL szanuje ustawienia lenistwa w twoich mapowaniach i gwarantuje, że załadowane zostanie to, co chcesz załadować. Oznacza to, że jedno zapytanie HQL może skutkować kilkoma bezpośrednimi instrukcjami SQL SELECT, aby pobrać podrozdział ze wszystkimi nieludzkimi odwzorowanymi powiązaniami i kolekcjami. Jeśli chcesz zmienić „jak”, a nawet „co”, użyj LEFT JOIN FETCH, aby włączyć pobieranie z zewnętrznym złączeniem dla konkretnej kolekcji lub zerować powiązanie typu wiele do jednego lub jeden do jednego, lub JOIN FETCH, aby włączyć pobieranie wewnętrznego połączenia dla niezerowalnego powiązania typu jeden do jednego lub jeden do jednego. Zapytania HQL nie uwzględniają żadnego fetch = „join” zdefiniowanego w dokumencie odwzorowania.
Varun Mehta
źródło
1
Tylko wskazując każdemu, kto przegląda. że ta odpowiedź pochodzi z 2008 roku. Może już tak nie być. dimovelev.blogspot.com/2015/02/…
Amalgovinus
41

Kryteria są obiektowym interfejsem API, podczas gdy HQL oznacza konkatenację łańcuchów. Oznacza to, że mają zastosowanie wszystkie zalety zorientowania obiektowego:

  1. Wszystkie pozostałe elementy są jednakowe, wersja OO jest nieco mniej podatna na błędy. Do zapytania HQL można dołączyć dowolny stary ciąg, natomiast tylko prawidłowe obiekty Criteria mogą przekształcić się w drzewo kryteriów. W efekcie klasy Criteria są bardziej ograniczone.
  2. Dzięki funkcji autouzupełniania OO jest łatwiejsze do wykrycia (a przez to łatwiejsze w użyciu, przynajmniej dla mnie). Nie musisz koniecznie pamiętać, które części zapytania idą gdzie; IDE może ci pomóc
  3. Nie musisz także pamiętać szczegółów składni (np. Które symbole idą gdzie). Wszystko, co musisz wiedzieć, to jak wywoływać metody i tworzyć obiekty.

Ponieważ HQL jest bardzo podobny do SQL (który większość deweloperów już bardzo dobrze zna), te argumenty „nie muszą pamiętać” nie mają tak dużej wagi. Gdyby HQL był bardziej różny, byłoby to ważniejsze.

Craig Walker
źródło
12
Argumenty te nie trzymają wody (w odniesieniu do HQL). Nie musi obejmować konkatenacji łańcuchów. To, że wersja OO jest mniej podatna na błędy, jest bezpodstawna. Jest równie podatny na błędy, ale innego rodzaju. Wysiłek związany z poznaniem metod wywoływania nie różni się tak bardzo od znajomości symboli wywoływanych w HQL (poważnie, nie rozwiązujemy tutaj PDE.)
luis.espinal
Czy są jakieś dobre przykłady, które pokazują, dlaczego HQL jest lepszy niż kryteria API w niektórych przypadkach? Przeczytałem koniec jednego bloga, ale nic nie zrozumiałem. Byłbym wdzięczny, gdybyś mógł pomóc. Dzięki. Link - javalobby.org/articles/hibernatequery102
Erran Morad
1
Zapytania o nazwie HQL są kompilowane w czasie wdrażania i w tym momencie wykrywane są brakujące pola (może z powodu złych refaktorów?). Myślę, że dzięki temu kod jest bardziej odporny i mniej podatny na błędy niż kryteria.
narduk
Automatyczne uzupełnianie w kryteriach jest prawie bezużyteczne, ponieważ właściwości są tylko ciągami znaków.
Lluis Martinez
35

Zwykle używam kryteriów, gdy nie wiem, jakie dane wejściowe zostaną wykorzystane na jakich fragmentach danych. Podobnie jak w formularzu wyszukiwania, w którym użytkownik może wprowadzić od 1 do 50 pozycji, a ja nie wiem, czego będzie szukał. Bardzo łatwo jest po prostu dodać więcej do kryteriów, gdy przechodzę przez sprawdzanie, czego szuka użytkownik. Myślę, że byłoby bardziej kłopotliwe, aby umieścić zapytanie HQL w takiej sytuacji. HQL jest świetny, gdy wiem dokładnie, czego chcę.

Arthur Thomas
źródło
1
To dobry komentarz. Obecnie budujemy bardzo duże ciągi znaków HQL dla formularza wyszukiwania, który zawiera wiele różnych obiektów poprzez połączenia. Wygląda brzydko. Sprawdzę, czy kryteria mogą to wyczyścić. Ciekawe ...
cbmeeks,
Dzięki. To jest doskonały przykład. Czy możesz prosić o więcej?
Erran Morad,
31

HQL jest znacznie łatwiejszy do odczytania, łatwiejszy do debugowania za pomocą narzędzi takich jak wtyczka Hibernacja Eclipse i łatwiejszy do logowania. Zapytania o kryteria są lepsze do tworzenia zapytań dynamicznych, w których wiele zachowań jest określanych w czasie wykonywania. Jeśli nie znasz SQL, rozumiem za pomocą zapytań Kryteria, ale ogólnie wolę HQL, jeśli wiem, czego chcę z góry.

Brian Deterling
źródło
22

Kryteria to jedyny sposób określenia naturalnych wyszukiwań kluczy, które korzystają ze specjalnej optymalizacji w pamięci podręcznej zapytań drugiego poziomu. HQL nie ma sposobu na określenie niezbędnej podpowiedzi.

Więcej informacji znajdziesz tutaj:

Alex Miller
źródło
21

Criteria Api to jedna z dobrych koncepcji Hibernacji. zgodnie z moim zdaniem są to mało punkt, w którym możemy zrobić różnicę między HQL i Criteria API

  1. HQL ma wykonywać zarówno operacje zaznaczania, jak i niewybrania danych, ale Kryteria służą tylko do wybierania danych, nie możemy wykonywać operacji niewybrania przy użyciu kryteriów.
  2. HQL nadaje się do wykonywania zapytań statycznych, natomiast jako kryteria nadaje się do wykonywania zapytań dynamicznych
  3. HQL nie obsługuje koncepcji podziału na strony , ale możemy osiągnąć podział na strony za pomocą kryteriów.
  4. Kryteria zajmowały więcej czasu niż HQL.
  5. Dzięki Criteria jesteśmy bezpieczni z SQL Injection ze względu na jego dynamiczne generowanie zapytań, ale w HQL, ponieważ twoje zapytania są stałe lub parametryzowane, nie ma bezpieczeństwa przed SQL Injection
Arvind
źródło
11
Kilka punktów Istnieje paginacja w HQL: możesz użyć limit offset:rows W hql możesz uniknąć iniekcji sql używającsetParameter
Viswanath Lekshmanan
13

Aby wykorzystać to, co najlepsze z obu światów, ekspresja i zwięzłość HQL oraz dynamiczny charakter Kryteriów rozważają użycie Querydsl .

Querydsl obsługuje JPA / Hibernate, JDO, SQL i Kolekcje.

Jestem opiekunem Querydsl, więc ta odpowiedź jest stronnicza.

Timo Westkämper
źródło
13

Dla mnie Kryteria są dość łatwe do zrozumienia i tworzenia zapytań dynamicznych. Ale wadą, którą do tej pory mówię, jest to, że ładuje wszystkie relacje wiele-jeden itp., Ponieważ mamy tylko trzy typy FetchModes, tj. Select, Proxy i Default, i we wszystkich tych przypadkach ładuje wiele-jeden (może się mylę, jeśli tak pomogę odpadam :))

Drugi problem z Criteria polega na tym, że ładuje pełny obiekt, tzn. Jeśli chcę po prostu załadować EmpName pracownika, to nie wymyśli tego instancji, wymyśli kompletny obiekt Employee i mogę uzyskać z niego EmpName z tego powodu, że naprawdę źle działa w raportowanie . gdzie jako HQL po prostu ładuj (nie ładowałem powiązań / relacji), czego chcesz, więc zwiększ wydajność wiele razy.

Jedną z cech Kryteriów jest to, że zabezpieczy cię przed SQL Injection ze względu na jego dynamiczne generowanie zapytań, gdzie tak jak w HQL, ponieważ twoje zapytania są albo stałe, albo sparametryzowane, więc nie są bezpieczne przed SQL Injection.

Również jeśli piszesz HQL w plikach ur aspx.cs, to jesteś ściśle powiązany z ur DAL.

Podsumowując, doszedłem do wniosku, że są miejsca, w których nie można żyć bez raportów typu HQL, więc używaj ich, w przeciwnym razie Kryteria są łatwiejsze do zarządzania.

Zafar
źródło
13
HQL NIE jest bezpieczny dla iniekcji SQL
Varun Mehta
Myślę, że kryteria nie są bezpieczne do wstrzykiwań. Zobacz mój post tutaj: stackoverflow.com/questions/6746486/…
Mister Smith,
4
HQL IS jest bezpieczny do wstrzykiwania SQL, dodając „setParameter”
Javatar
2
@Zafar: możesz wybrać tylko niektóre właściwości bytu za pomocą rzutów
Răzvan Flavius ​​Panda
@Zafar można ustawić rzut w zapytaniu kryteriów, aby wybrać poszczególne kolumny. Możesz pobrać EmpName, nie musisz pobierać całego obiektu.
Khatri
12

Kryteria API

Criteria API lepiej nadaje się do dynamicznie generowanych zapytań. Jeśli więc chcesz dodać filtry klauzul WHERE, klauzule JOIN lub zmienić klauzulę ORDER BY lub kolumny projekcji, interfejs API Criteria może pomóc w dynamicznym wygenerowaniu zapytania w sposób, który zapobiega atakom SQL Injection .

Z drugiej strony zapytania Criteria są mniej wyraziste i mogą nawet prowadzić do bardzo skomplikowanych i nieefektywnych zapytań SQL, jak wyjaśniono w tym artykule .

JPQL i HQL

JPQL jest standardowym językiem zapytań encji JPA, podczas gdy HQL rozszerza JPQL i dodaje pewne funkcje specyficzne dla Hibernacji.

JPQL i HQL są bardzo ekspresyjne i przypominają SQL. W przeciwieństwie do Criteria API, JPQL i HQL ułatwiają przewidywanie bazowego zapytania SQL generowanego przez dostawcę JPA. Znacznie łatwiej jest również przejrzeć zapytania HQL niż kryteria.

Warto zauważyć, że wybór encji za pomocą JPQL lub Criteria API ma sens, jeśli trzeba je zmodyfikować. W przeciwnym razie projekcja DTO jest znacznie lepszym wyborem.

Wniosek

Jeśli nie musisz zmieniać struktury zapytań encji, użyj JPQL lub HQL. Jeśli chcesz zmienić kryteria filtrowania lub sortowania lub zmienić projekcję, użyj interfejsu API Criteria.

Jednak tylko dlatego, że używasz JPA lub Hibernacji, nie oznacza to, że nie powinieneś używać natywnego SQL. Zapytania SQL są bardzo przydatne, a JPQL i API kryteriów nie zastępują SQL. Sprawdź ten artykuł, aby uzyskać więcej informacji na ten temat.

Vlad Mihalcea
źródło
11

Dla mnie największą wygraną w Criteria jest Przykład API, w którym można przekazać obiekt, a hibernacja zbuduje zapytanie w oparciu o te właściwości obiektu.

Poza tym API kryteriów ma swoje dziwactwa (uważam, że zespół hibernacji przerabia API), takie jak:

  • a kryteria.createAlias ​​(„obj”) wymusza połączenie wewnętrzne zamiast możliwego połączenia zewnętrznego
  • nie możesz utworzyć tego samego aliasu dwa razy
  • niektóre klauzule sql nie mają prostych odpowiedników kryteriów (jak podselekcja)
  • itp.

Zwykle używam HQL, gdy chcę zapytań podobnych do SQL (usuń z użytkowników, gdzie status = „zablokowany”), i zwykle używam kryteriów, gdy nie chcę używać ciągów znaków.

Kolejną zaletą HQL jest to, że możesz zdefiniować wszystkie zapytania wcześniej, a nawet eksternalizować je do pliku.

Miguel Ping
źródło
9

Kryteria API zapewniają jedną odrębną funkcję, której nie zapewnia ani SQL, ani HQL. to znaczy. umożliwia sprawdzenie czasu kompilacji zapytania.

użytkownik1165443
źródło
7

Na początku używaliśmy głównie kryteriów w naszej aplikacji, ale później została ona zastąpiona przez HQL ze względu na problemy z wydajnością.
Używamy głównie bardzo złożonych zapytań z kilkoma złączeniami, co prowadzi do wielu zapytań w Kryteriach, ale jest bardzo zoptymalizowane w HQL.
Chodzi o to, że używamy tylko kilku proroctw dotyczących konkretnego obiektu, a nie obiektów kompletnych. W przypadku kryteriów problemem była także konkatenacja łańcuchów znaków.
Powiedzmy, że jeśli chcesz wyświetlić imię i nazwisko użytkownika w HQL, jest to dość łatwe, (name || ' ' || surname)ale w Crteria nie jest to możliwe.
Aby temu zaradzić, użyliśmy ResultTransormers, w którym istniały metody, w których zastosowano taką konkatenację dla potrzebnego wyniku.
Dziś używamy głównie HQL w następujący sposób:

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

więc w naszym przypadku zwrócone rekordy są mapami potrzebnych właściwości.

Bojan Kraut
źródło
1
Dzięki Criteria możesz użyć org.hibernate.criterion.CriteriaSpecification.ALIAS_TO_ENTITY_MAP
AA.
Zwracanie listy map z mojego doświadczenia ma bardzo niską wydajność. Wolę zwrócić listę tablic obiektów lub listę ziaren (zawsze możesz zdefiniować fasolę, która pasuje do określonego zestawu wyników).
Lluis Martinez,
7
  • HQL ma wykonywać zarówno operacje zaznaczania, jak i niewybrania danych, ale Kryteria służą tylko do wybierania danych, nie możemy wykonywać operacji niewybrania za pomocą kryteriów
  • HQL nadaje się do wykonywania zapytań statycznych, natomiast jako kryteria nadaje się do wykonywania zapytań dynamicznych
  • HQL nie obsługuje koncepcji podziału na strony, ale możemy osiągnąć podział na strony za pomocą kryteriów
  • Kryteria zajmowały więcej czasu niż wykonanie HQL
  • Dzięki Criteria jesteśmy bezpieczni z SQL Injection ze względu na jego dynamiczne generowanie zapytań, ale w HQL, ponieważ twoje zapytania są albo stałe, albo sparametryzowane, nie ma bezpieczeństwa przed SQL Injection.

źródło

Premraj
źródło
Aby to wyjaśnić, zapytania o kryteria przy użyciu interfejsu API kryteriów programu Hibernate mogą być dostępne do tworzenia zapytań, ale zapytania o kryteria JPA obejmują wybory, aktualizacje i usunięcia. Zobacz CriteriaUpdate<T>i w CriteriaDelete<T>celach informacyjnych.
Naros
5

Kryterium zapytania dynamicznie możemy konstruować zapytanie na podstawie naszych danych wejściowych. W przypadku zapytania Hql jest to zapytanie statyczne po zbudowaniu, nie możemy zmienić jego struktury.

użytkownik1679378
źródło
2
Skąd. Za pomocą HQL można ustawić właściwości za pomocą identyfikatora „:”, a następnie zastąpić te właściwości unikalnymi wartościami. Na przykład zapytanie q = session.createQuery („SELECT: aValue FROM my_table”); a następnie q.setParameter („aValue”, „some_column_name”);
MattC,
@MattC W swoim przykładzie zmieniasz wartości parametrów, a nie strukturę zapytania.
Czar
4

Nie chcę tu kopać martwego konia, ale ważne jest, aby wspomnieć, że zapytania dotyczące kryteriów są już nieaktualne. Użyj HQL.

Eskir
źródło
1

Wolę też zapytania o kryteria dla zapytań dynamicznych. Ale wolę hql do usuwania zapytań, na przykład, jeśli usuń wszystkie rekordy z tabeli potomnej dla identyfikatora nadrzędnego „xyz”, jest to łatwe do osiągnięcia przez HQL, ale dla kryteriów API najpierw musimy uruchomić n liczbę zapytań o usunięcie, gdzie n jest liczbą potomków rekordy tabeli.

Punit Patel
źródło
0

Większość odpowiedzi tutaj wprowadza w błąd i wspomina, że Criteria Queriessą one wolniejsze niż HQL, co w rzeczywistości nie jest prawdą.

Jeśli zagłębisz się i wykonasz kilka testów, zobaczysz, że zapytania o kryteria działają znacznie lepiej niż zwykły HQL .

A także dzięki Criteria Query masz kontrolę obiektową, której nie ma w HQL .

Aby uzyskać więcej informacji, przeczytaj tę odpowiedź tutaj .

Pritam Banerjee
źródło
0

Jest inny sposób. Skończyłem z utworzeniem parsera HQL opartego na hibernacji oryginalnej składni, więc najpierw parsuje HQL, a następnie może dynamicznie wstrzykiwać parametry dynamiczne lub automatycznie dodawać niektóre popularne filtry do zapytań HQL. Działa świetnie!

Wallace Peng
źródło
0

Ten post jest dość stary. Większość odpowiedzi mówi o kryteriach hibernacji, a nie o kryteriach JPA. JPA 2.1 dodał CriteriaDelete / CriteriaUpdate i EntityGraph, które kontrolują, co dokładnie należy pobrać. Kryteria API jest lepsze, ponieważ Java to OO. Właśnie dlatego powstaje JPA. Po skompilowaniu JPQL zostanie ono przetłumaczone na drzewo AST (model OO) przed przetłumaczeniem na SQL.

Słoneczny dzień
źródło
-3

HQL może powodować problemy związane z bezpieczeństwem, takie jak wstrzykiwanie SQL.

Emad Aghayi
źródło
11
Problemy te nie są spowodowane przez HQL, ale przez brak zrozumienia podstawowych praktyk rozwoju oprogramowania. Potrafię również tworzyć kod podatny na ataki typu sql injection z wykorzystaniem kryteriów API.
Jens Schauder,
1
To tak, jakby powiedzieć „odpytywanie RDBMS z Javy może powodować obawy związane z bezpieczeństwem wstrzykiwania SQL”: D
Czar