JPA ve Hibernate - Kriterler - JPQL veya HQL karşılaştırması


295

Ölçüt veya HQL kullanmanın avantajları ve dezavantajları nelerdir? Ölçüt API'sı, Hazırda Bekletme'deki sorguları ifade etmenin güzel bir nesne yönelimli yöntemidir, ancak bazen Ölçüt Sorgularını anlamak / oluşturmak HQL'den daha zordur.

Kriterleri ne zaman ve ne zaman HQL kullanıyorsunuz? Hangi kullanım durumlarında neyi tercih edersiniz? Yoksa sadece bir tat meselesi mi?


Doğru cevap 'kullanım durumuna bağlıdır' olacaktır.
Hace

Peki ya bu araç ? Ortak sorguların nesne olarak oluşturulmasına izin verir: korumalı Madde select () {return em.select ("DISTINCT i") .from (this.getName (), "i") .joinFetch ("i.locale lf") } public T findBySlug (String slug) {dönüş (T) this.select () .join ("i.locale l"); .where ("l.slug =?", slug) .fetchSingle (); }
Vojtěch

1
Görüş temelli bir sorunun tanımı, ancak insanlar siteyi kapatma fırsatını bulamadı ... SSS

Yanıtlar:


212

Dinamik sorgular için çoğunlukla Ölçüt Sorgularını tercih ederim. Örneğin, bazı parametrelere bağlı olarak bazı siparişleri dinamik olarak eklemek veya bazı parçaları (ör. Kısıtlamalar) dışarıda bırakmak çok daha kolaydır.

Diğer yandan statik ve karmaşık sorgular için HQL kullanıyorum, çünkü HQL'i anlamak / okumak çok daha kolay. Ayrıca, HQL biraz daha güçlü, bence, örneğin farklı birleştirme türleri için.


13
Ayrıca, Ölçütler biraz daha güvenli görünüyor olsa da, kendinizi güvende hissetmenizi sağlayacak tek şey test etmektir.

Bazı durumlarda HQL'nin neden api ölçütlerinden daha iyi olduğunu gösteren iyi örnekler var mı? Bir blogun sonunu okudum ama hiçbir şey anlamadım. Eğer yardımcı olabilir eğer takdir ediyorum. Teşekkürler. Link - javalobby.org/articles/hibernatequery102
Erran Morad

Yukarıdaki tüm nedenler - Kriterleri HQL'e de tercih ederim çünkü programcı için daha güvenlidir, kodlama hatalarını azaltır - HQL dizesindeki derleme doğrulanmamıştır.
nuno

Bununla birlikte, sayfalama yaparken farklı varlıkları alma sorunu vardır. Bunu yaparken sorunları önlemek için HQL seçerim ...
Anthony Webster

sütun adları için bir metamodel ile ölçüt sorgusu kullanmak, yeniden düzenleme sırasında hiçbir şeyi kırmamaya ve koddaki tüm oluşumları yeniden adlandırmak için modern bir IDE'den basit bir komutla yardımcı olur.
Massimo

92

HQL ve ölçütQuery arasında performans açısından bir fark vardır, ölçütQuery kullanarak bir sorgu her başlattığınızda, tablo adı için herhangi bir DB için son sorgulanan önbelleğe yansıtmayan yeni bir diğer ad oluşturur. Bu, oluşturulan SQL'in derlenmesi ve yürütülmesi daha fazla zaman alan bir ek yüke yol açar.

Getirme stratejileri hakkında [http://www.hibernate.org/315.html]

  • Ölçütler, eşlemelerinizdeki tembellik ayarlarına uyar ve yüklenmesini istediğiniz şeyin yüklenmesini garanti eder. Bu, bir Ölçüt sorgusunun, tembel olmayan tüm eşleşmiş ilişkilendirmeler ve koleksiyonlarla alt grafiği getirmesi için birkaç SQL derhal SELECT deyimiyle sonuçlanabileceği anlamına gelir. "Nasıl" ve hatta "ne" değerini değiştirmek istiyorsanız, belirli bir koleksiyon veya ilişkilendirme için dış birleştirme getirmeyi etkinleştirmek veya devre dışı bırakmak için setFetchMode () öğesini kullanın. Ölçüt sorguları da getirme stratejisine tamamen saygı gösterir (birleştirme vs seçme ve alt seçim).
  • HQL, eşlemelerinizdeki tembellik ayarlarına uyar ve yüklenmesini istediğiniz şeyin yüklenmesini garanti eder. Bu, bir HQL sorgusunun, tembel olmayan tüm eşleşmiş ilişkilendirmeler ve koleksiyonlarla alt grafiği getirmesi için birkaç SQL anında SELECT deyimiyle sonuçlanabileceği anlamına gelir. "Nasıl" ve hatta "ne" yi değiştirmek istiyorsanız, belirli bir koleksiyon için dış birleşim getirmeyi etkinleştirmek için SOL BİRLEŞTİR FETCH'i veya etkinleştirmek için bire bir veya bire bir ilişkilendirmeyi veya etkinleştirmek için BİRLEŞTİR FETCH'i kullanın null olmayan bire bir veya bire bir ilişki için iç birleşim getirme. HQL sorguları, eşleme belgesinde tanımlanan herhangi bir fetch = "join" öğesine uymaz.

1
Sadece göz atan herkese işaret ediyor. bu cevabın 2008'den geldiğini söyleyebiliriz. dimovelev.blogspot.com/2015/02/…
Amalgovinus

41

Ölçütler nesne yönelimli bir API, HQL ise dize birleştirme anlamına gelir. Bu, nesne yönelimliğin tüm faydalarının geçerli olduğu anlamına gelir:

  1. Diğer her şey eşit olduğunda, OO sürümü hataya daha az eğilimlidir. Herhangi bir eski dize HQL sorgusuna eklenebilirken, yalnızca geçerli Ölçüt nesneleri bir Ölçüt ağacına girebilir. Etkili olarak, Ölçüt sınıfları daha kısıtlıdır.
  2. Otomatik tamamlama ile OO daha keşfedilebilirdir (ve en azından benim için kullanımı daha kolaydır). Sorgunun hangi bölümlerinin nereye gittiğini hatırlamanız gerekmez; IDE size yardımcı olabilir
  3. Ayrıca sözdiziminin ayrıntılarını da hatırlamanız gerekmez (hangi sembollerin nereye gittiğine benzer). Bilmeniz gereken tek şey yöntemlerin nasıl çağrılacağı ve nesnelerin nasıl yaratılacağıdır.

HQL, SQL'e çok benzediğinden (çoğu geliştirici zaten çok iyi biliyor), bu "hatırlamak zorunda değilsiniz" argümanları çok fazla ağırlık taşımıyor. HQL daha farklı olsaydı, bu daha önemli olurdu.


12
Bu argümanlar su içermez (HQL ile ilgili olarak). Dize birleştirme içermesi gerekmez. OO versiyonunun hatalara daha az eğilimli olması asılsızdır. Hatalara eşit derecede eğilimlidir, ancak farklı bir türdür. Hangi yöntemleri arayacağınızı bilmenin çabası,
HQL'de

Bazı durumlarda HQL'nin neden api ölçütlerinden daha iyi olduğunu gösteren iyi örnekler var mı? Bir blogun sonunu okudum ama hiçbir şey anlamadım. Eğer yardımcı olabilir eğer takdir ediyorum. Teşekkürler. Bağlantı - javalobby.org/articles/hibernatequery102
Erran Morad

1
HQL olarak adlandırılan sorgular konuşlandırma zamanında derlenir ve bu noktada eksik alanlar (belki de kötü refaktörler için?) Algılanır. Bu kod daha esnek ve aslında daha az hata ölçütlere eğilimli yapmak düşünüyorum.
narduk

Kriterler'de otomatik tamamlama neredeyse işe yaramaz, çünkü özellikler sadece dizelerdir.
Lluis Martinez

35

Hangi veri parçalarında hangi girdilerin kullanılacağını bilmediğimde genellikle Ölçütleri kullanırım. Kullanıcının 1 ila 50 öğeden herhangi birini girebileceği bir arama formunda olduğu gibi, ne arayacaklarını bilmiyorum. Kullanıcının ne aradığını kontrol ederken kriterlere daha fazlasını eklemek çok kolay. Bu durumda bir HQL sorgusu koymak biraz daha zahmetli olacağını düşünüyorum. Ne istediğimi tam olarak bildiğimde HQL harika.


1
Bu iyi bir yorum. Şu anda, birleştirmeler yoluyla birçok farklı nesne içeren bir arama formu için çok büyük HQL dizeleri oluşturuyoruz. Çirkin gözüküyor. Bir kriterin bunu temizleyip temizleyemeyeceğini görecek. İlginç ...
cbmeeks

Teşekkürler. Bu mükemmel bir örnek. Bana biraz daha verebilir misin?
Erran Morad

31

HQL'in okunması çok daha kolay, Eclipse Hibernate eklentisi gibi araçları kullanarak hata ayıklaması daha kolay ve günlüğü daha kolay. Ölçüt sorguları, çalışma zamanında bir çok davranışın belirlendiği dinamik sorgular oluşturmak için daha iyidir. SQL bilmiyorsanız, Ölçüt sorgularını kullanarak anlayabiliyordum, ancak önceden ne istediğimi biliyorsanız genel olarak HQL'i tercih ederim.



21

Ölçüt Api, Hibernate'in iyi konseptlerinden biridir. Benim görüşüme göre, bunlar HQL ve Criteria Api arasında fark yaratabileceğimiz birkaç nokta

  1. HQL, veriler üzerinde hem seçili hem de seçili olmayan işlemleri gerçekleştirmektir, ancak Ölçütler yalnızca verileri seçmek içindir, ölçütleri kullanarak seçili olmayan işlemleri gerçekleştiremeyiz.
  2. HQL, Statik Sorguları yürütmek için uygundur; burada Kriterler Dinamik Sorguları yürütmek için uygundur
  3. HQL sayfalama kavramını desteklemez , ancak Ölçütlerle sayfalandırmayı başarabiliriz.
  4. Yürütülmesi gereken kriterler HQL'den daha uzun sürüyordu.
  5. Ölçütler ile dinamik sorgu oluşturma nedeniyle SQL Enjeksiyonu ile güvende oluruz, ancak sorgularınız sabit veya parametreli olduğu için HQL'de SQL Enjeksiyonu için güvenli değildir.

11
Noktalarının Çift Sayfalandırma HQL içinde vardır: kullanabileceğiniz limit offset:rows hql olarak kullanmakta sql enjeksiyon önleyebilirsinizsetParameter
Viswanath Lekshmanan

13

Her iki dünyanın en iyisini kullanmak için, HQL'in ifade ve kısalığı ile Kriterlerin dinamik doğası Querydsl kullanmayı düşünür .

Querydsl, JPA / Hibernate, JDO, SQL ve Koleksiyonlarını destekler.

Ben Querydsl'in koruyucusuyum, bu yüzden bu cevap taraflı.


13

Benim için Kriterleri Anlamak ve Dinamik sorgular yapmak oldukça kolaydır. Ama şimdiye kadar söylediğim kusur, birçok çoklu vb ilişkisini yüklediğidir, çünkü Select, Proxy ve Default gibi yalnızca üç tip var ve tüm bu durumlarda birden fazla yüklüyor (eğer yardım edersem yanlış olabilirim) beni dışarı :))

Kriterler ile 2. sorun yani tam bir nesne yükler yani ben sadece bir çalışanın EmpName yüklemek istiyorsanız bu tam bir Çalışan nesnesi ile gelip bu insted ile gelmeyecek ve bu gerçekten kötü çalışması nedeniyle EmpName alabilirsiniz raporlama . nerede HQL olarak sadece yük (ilişkilendirme / ilişkiler yüklemedi) u istediğin kadar performans birçok kez artırmak.

Ölçütlerin bir özelliği, dinamik sorgu oluşturma nedeniyle ur sorguları sabit veya parametreli olduğu için SQL Enjeksiyonundan güvenli olmadığı dinamik sorgu oluşturma nedeniyle u SQL Enjeksiyonundan korunacaktır.

Ayrıca ur aspx.cs dosyalarına HQL yazarsanız, ur DAL ile sıkıca bağlanırsınız.

Genel olarak benim sonucum u raporlar gibi HQL olmadan yaşayamayacağınız yerler vardır, bu yüzden onları kullanın Kriterler yönetmek daha kolaydır.


13
HQL SQL enjeksiyon için güvenli DEĞİLDİR
Varun Mehta

Bence Kriterler enjeksiyon için güvenli değil. Yazımı buradan görebilirsiniz: stackoverflow.com/questions/6746486/…
Mister Smith


2
@Zafar: projeksiyonları kullanarak bir varlığın sadece belirli özelliklerini seçebilirsiniz
Răzvan Flavius ​​Panda

@Zafar, belirli sütunları seçmek için ölçüt sorgusundaki projeksiyonu ayarlayabilirsiniz. EmpName'i getirebilirsiniz, tüm nesneyi getirmeye gerek yoktur.
Khatri

12

Ölçüt API'sı

Ölçüt API'sı, dinamik olarak oluşturulan sorgular için daha uygundur. Bu nedenle, WHERE yan tümcesi filtreleri, JOIN yan tümceleri eklemek veya ORDER BY yan tümcesini veya projeksiyon sütunlarını değiştirmek istiyorsanız, Ölçüt API'si sorguyu SQL Enjeksiyon saldırılarını önleyecek şekilde dinamik olarak oluşturmanıza yardımcı olabilir .

Öte yandan, Ölçüt sorguları daha az ifade edicidir ve bu makalede açıklandığı gibi çok karmaşık ve verimsiz SQL sorgularına bile yol açabilir .

JPQL ve HQL

JPQL, JPA standart varlık sorgu dilidir, HQL ise JPQL'i genişletir ve Hazırda Bekleme özel bazı özellikler ekler.

JPQL ve HQL çok etkileyici ve SQL'e benziyor. Ölçüt API'sinin aksine, JPQL ve HQL, JPA sağlayıcısı tarafından oluşturulan temel SQL sorgusunu tahmin etmeyi kolaylaştırır. Kişinin HQL sorgularını incelemek, Ölçütlerden daha kolaydır.

JPQL veya Criteria API ile varlık seçmenin, değiştirmeniz gerektiğinde mantıklı olduğunu belirtmek gerekir. Aksi takdirde, bir DTO projeksiyonu çok daha iyi bir seçimdir.

Sonuç

Varlık sorgu yapısını değiştirmeniz gerekmiyorsa, JPQL veya HQL kullanın. Filtreleme veya sıralama ölçütlerini değiştirmeniz veya projeksiyonu değiştirmeniz gerekiyorsa, Ölçüt API'sını kullanın.

Ancak, JPA veya Hazırda Bekletme kullandığınız için, yerel SQL kullanmamanız gerektiği anlamına gelmez. SQL sorguları çok kullanışlıdır ve JPQL ve Criteria API, SQL'in yerini almaz. Bu konu hakkında daha fazla bilgi için bu makaleye göz atın .



11

Benim için Ölçütlerdeki en büyük kazanç, bir nesneyi geçirebileceğiniz ve hazırda bekletme modunun bu nesne özelliklerine dayalı bir sorgu oluşturacağı Örnek API'dir.

Bunun yanı sıra, kriter API'sının tuhaflıkları var (hazırda bekletme ekibinin API'yi yeniden çalıştığına inanıyorum):

  • bir ölçüt.createAlias ​​("obj") olası bir dış birleşim yerine bir iç birleşimi zorlar
  • aynı takma adı iki kez oluşturamazsınız
  • bazı sql cümlelerinin basit kıstasları yoktur (bir alt seçim gibi)
  • vb.

Ben sql (sorgu = status = 'bloke' nerede kullanıcılardan silmek) benzer sorgular istediğinizde HQL kullanma eğilimindedir ve ben dize ekleme kullanmak istemiyorum zaman ölçütleri kullanmak eğilimindedir.

HQL'in bir başka avantajı da, tüm sorgularınızı önceden tanımlamanız ve hatta bunları bir dosyaya dışsallaştırmanızdır.


9

Ölçüt api'si, SQL veya HQL'in sağlamadığı tek bir özellik sağlar. yani. bir sorgunun derleme zaman kontrolünü sağlar.


7

Başlangıçta uygulamamızda ağırlıklı olarak Kriterler kullandık, ancak performans sorunları nedeniyle HQL ile değiştirildikten sonra.
Temel olarak, Kriterler'de birden çok sorguya yol açan ancak HQL'de çok optimize edilen birkaç birleştirmeyle çok karmaşık sorgular kullanıyoruz.
Durum, belirli nesnelerde sadece birkaç özellik kullanmamızdır, tam nesneler değil. Ölçütlerde sorun dize birleştirmesiydi.
Diyelim ki kullanıcının adını ve soyadını (name || ' ' || surname)HQL'de göstermeniz gerekiyorsa oldukça kolaydır, ancak Crteria'da bu mümkün değildir.
Bunun üstesinden gelmek için, gerekli sonuç için bu tür bir birleştirmenin uygulandığı yöntemlerin bulunduğu ResultTransormers'ı kullandık.
Bugün ağırlıklı olarak HQL kullanıyoruz:

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

yani bizim durumumuzda iade edilen kayıtlar gerekli özelliklerin haritalarıdır.


1
Ölçütler ile org.hibernate.criterion.CriteriaSpecification.ALIAS_TO_ENTITY_MAP
AA

Deneyimlerime göre bir harita listesi döndürmek çok kötü bir performansa sahip. Nesne dizilerinin veya fasulye listelerinin listesini döndürmeyi tercih ederim (her zaman özel sonuç kümenize uyan bir fasulye tanımlayabilirsiniz).
Lluis Martinez

7
  • HQL, veriler üzerinde hem seçili hem de seçili olmayan işlemleri gerçekleştirmek içindir, ancak Ölçütler yalnızca verileri seçmek içindir, ölçütleri kullanarak seçili olmayan işlemleri gerçekleştiremeyiz
  • HQL, Statik Sorguları yürütmek için uygundur; burada Kriterler Dinamik Sorguları yürütmek için uygundur
  • HQL sayfalama kavramını desteklemez, ancak Ölçütlerle sayfalandırmayı başarabiliriz
  • HQL'den sonra yürütmek için daha fazla zaman alan kriterler
  • Ölçütler ile dinamik sorgu oluşturma nedeniyle SQL Enjeksiyonu ile güvende oluruz, ancak sorgularınız sabit veya parametrelendirildiği için HQL'de SQL Enjeksiyonundan güvenli değildir.

kaynak


Açıklığa kavuşturmak için, Hazırda Bekletme Ölçütleri API'sini kullanan ölçüt sorguları sorgulama için kullanılabilir, ancak JPA ölçütleri sorguları seçimleri, güncellemeleri ve silmeleri kapsar. Bakınız CriteriaUpdate<T>ve CriteriaDelete<T>.
Naros

5

Dinamik olarak ölçüt sorgusu girdilerimize dayanarak sorgu oluşturabiliriz .. Hql sorgusu durumunda statik sorgu olması durumunda, sorgu yapısını değiştiremeyiz.


2
Öyle değil. HQL ile özellikleri ':' tanımlayıcı ile ayarlayabilir ve daha sonra bu özellikleri benzersiz değerlerle değiştirebilirsiniz. Örneğin, Query q = session.createQuery ("SELECT: aValue FROM my_table"); ve sonra q.setParameter ("aValue", "some_column_name");
MattC

@MattC Örneğin, sorgunun yapısını değil parametrelerin değerlerini değiştiriyorsunuz.
Çar

4

Burada ölü bir atı tekmelemek istemiyorum, ancak Ölçüt sorgularının artık kullanımdan kaldırıldığını belirtmek önemlidir. HQL kullanın.


1

Ayrıca dinamik sorgular için Ölçüt Sorgularını tercih ediyorum. Ancak, silme sorguları için hql'i tercih ediyorum, örneğin 'xyz' üst kimliği için alt tablodaki tüm kayıtları silerseniz, HQL tarafından kolayca elde edilir, ancak önce ölçütler API için n'nin alt öğe olduğu n silme sorgusu sayısını tetiklemeliyiz tablo kayıtları.


0

Buradaki cevapların çoğu yanıltıcıdır ve bundan Criteria Queriesdaha yavaş olduğunu belirtmektedir HQL, ki aslında durum böyle değildir.

Derinlemesine araştırırsanız ve bazı testler yaparsanız, Ölçüt Sorgularının normal HQL'den çok daha iyi performans gösterdiğini göreceksiniz .

Ayrıca Kriterler Sorgusu ile HQL'de olmayan Nesneye Dayalı kontrol elde edersiniz .

Daha fazla bilgi için bu cevabı buradan okuyun .


0

Başka bir yol var. Hazırda bekletme orijinal sözdizimine dayalı bir HQL ayrıştırıcı oluşturma ile sona erdi, böylece önce HQL ayrıştırmak sonra dinamik parametreleri enjekte veya otomatik olarak HQL sorguları için bazı ortak filtreler ekleyebilir. Harika çalışıyor!


0

Bu yazı oldukça eski. Çoğu yanıt, Hazırda Bekleme ölçütlerinden bahseder, JPA ölçütlerinden değil. JPA 2.1, tam olarak neyin getirileceğini kontrol eden CriteriaDelete / CriteriaUpdate ve EntityGraph'ı ekledi. Java OO olduğundan Ölçüt API'sı daha iyidir. Bu yüzden JPA oluşturulur. JPQL derlendiğinde, SQL'e çevrilmeden önce AST ağacına (OO modeli) çevrilecektir.


-3

HQL, SQL enjeksiyonu gibi güvenlik sorunlarına neden olabilir .


11
Bu sorunlara HQL değil, temel yazılım geliştirme uygulamalarının anlaşılmaması neden olmaktadır. Ben de kriterler api ile sql enjeksiyon saldırıları eğilimli kod oluşturabilirsiniz.
Jens Schauder

1
"Java'dan bir RDBMS'yi sorgulamak SQL enjeksiyon güvenliği sorunlarına neden olabilir"
Çar
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.