JPA dan Hibernate - Kriteria vs. JPQL atau HQL

295

Apa pro dan kontra menggunakan Kriteria atau HQL ? API Kriteria adalah cara berorientasi objek yang bagus untuk mengekspresikan kueri dalam Hibernate, tetapi kadang-kadang Kriteria Kueri lebih sulit dipahami / dibangun daripada HQL.

Kapan Anda menggunakan Kriteria dan kapan HQL? Apa yang Anda sukai dalam kasus penggunaan mana? Atau itu hanya masalah selera?

cretzel
sumber
Jawaban yang tepat adalah 'tergantung pada use case'.
Hace
Dan bagaimana dengan alat ini ? Ini memungkinkan untuk membuat kueri umum dengan cara objek: protected Klausa select () {return em.select ("DISTINCT i") .dari (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
Definisi pertanyaan berdasarkan opini, namun orang belum mengambil kesempatan untuk menutupnya ... sesuai situs FAQ

Jawaban:

212

Saya lebih suka Queri Kriteria untuk kueri dinamis. Misalnya, jauh lebih mudah untuk menambahkan beberapa pemesanan secara dinamis atau mengabaikan beberapa bagian (misalnya pembatasan) tergantung pada beberapa parameter.

Di sisi lain saya menggunakan HQL untuk query statis dan kompleks, karena jauh lebih mudah untuk memahami / membaca HQL. Juga, HQL sedikit lebih kuat, saya pikir, misalnya untuk tipe gabungan yang berbeda.

cretzel
sumber
13
Selain itu, meskipun Kriteria terlihat sedikit lebih aman, satu-satunya hal yang dapat membuat Anda merasa aman adalah pengujian.
Apakah ada contoh bagus yang menunjukkan mengapa HQL lebih baik daripada kriteria api dalam kasus tertentu? Saya membaca akhir dari satu blog, tetapi tidak mengerti apa-apa. Akan sangat menghargai jika Anda bisa membantu. Terima kasih. Tautan - javalobby.org/articles/hibernatequery102
Erran Morad
Semua alasan di atas - Saya juga lebih suka Kriteria untuk HQL karena lebih aman untuk programmer, mengurangi kesalahan pengkodean - kompilasi pada string HQL tidak divalidasi.
nuno
Namun, ada masalah mengambil entitas yang berbeda saat membuat halaman. Ketika melakukan ini, saya akan memilih HQL untuk menghindari masalah ...
Anthony Webster
menggunakan kueri kriteria dengan metamodel untuk nama kolom membantu selama refactoring untuk tidak merusak apa pun dan dengan perintah sederhana dari IDE modern untuk mengganti nama semua kejadian dalam kode.
Massimo
92

Ada perbedaan dalam hal kinerja antara HQL dan criteriaQuery, setiap kali Anda menjalankan kueri menggunakan criteriaQuery, itu membuat alias baru untuk nama tabel yang tidak mencerminkan dalam cache kueri terakhir untuk setiap DB. Ini mengarah ke overhead mengkompilasi SQL yang dihasilkan, mengambil lebih banyak waktu untuk dieksekusi.

Mengenai strategi pengambilan [http://www.hibernate.org/315.html]

  • Kriteria menghargai pengaturan kemalasan dalam pemetaan Anda dan menjamin apa yang Anda inginkan dimuat. Ini berarti satu permintaan Kriteria dapat menghasilkan beberapa pernyataan SELECT langsung SQL untuk mengambil subgraph dengan semua asosiasi dan koleksi yang tidak dipetakan. Jika Anda ingin mengubah "bagaimana" dan bahkan "apa", gunakan setFetchMode () untuk mengaktifkan atau menonaktifkan join luar yang mengambil koleksi atau asosiasi tertentu. Pertanyaan kriteria juga sepenuhnya menghormati strategi pengambilan (gabung vs pilih vs subselect).
  • HQL menghargai pengaturan kemalasan dalam pemetaan Anda dan menjamin apa yang Anda inginkan dimuat. Ini berarti satu permintaan HQL dapat menghasilkan beberapa pernyataan SELECT langsung SQL untuk mengambil subgraph dengan semua asosiasi dan koleksi yang tidak dipetakan. Jika Anda ingin mengubah "bagaimana" dan bahkan "apa", gunakan LEFT JOIN FETCH untuk memungkinkan penggabungan luar mengambil koleksi tertentu atau nullable banyak-ke-satu atau satu-ke-satu asosiasi, atau GABUNGKAN FETCH untuk mengaktifkan gabung batin mengambil untuk asosiasi banyak-ke-satu atau satu-ke-satu yang tidak dapat dibatalkan. Kueri HQL tidak menghormati fetch = "join" yang ditentukan dalam dokumen pemetaan.
Varun Mehta
sumber
1
Hanya menunjukkan kepada siapa saja yang menjelajah. bahwa jawaban ini berasal dari tahun 2008. ini mungkin bukan masalahnya lagi. dimovelev.blogspot.com/2015/02/...
Amalgovinus
41

Kriteria adalah API berorientasi objek, sedangkan HQL berarti penggabungan string. Itu berarti semua manfaat dari berorientasi objek berlaku:

  1. Semuanya sama, versi OO agak kurang rentan terhadap kesalahan. Setiap string lama dapat ditambahkan ke kueri HQL, sedangkan hanya objek Kriteria yang valid yang dapat membuatnya menjadi pohon Kriteria. Secara efektif, kelas Kriteria lebih terbatas.
  2. Dengan pelengkapan otomatis, OO lebih mudah ditemukan (dan setidaknya lebih mudah digunakan, bagi saya). Anda tidak perlu mengingat bagian kueri mana yang digunakan; IDE dapat membantu Anda
  3. Anda juga tidak perlu mengingat rincian sintaks (seperti simbol mana yang digunakan). Yang perlu Anda ketahui adalah cara memanggil metode dan membuat objek.

Karena HQL sangat mirip dengan SQL (yang sebagian besar devs sudah kenal dengan baik) maka argumen "tidak harus diingat" ini tidak terlalu berpengaruh. Jika HQL lebih berbeda, maka ini akan lebih penting.

Craig Walker
sumber
12
Argumen ini tidak tahan air (sehubungan dengan HQL). Tidak harus melibatkan penggabungan string. Bahwa versi OO kurang rentan terhadap kesalahan tidak berdasar. Ini sama-sama rentan terhadap kesalahan tetapi dari jenis yang berbeda. Upaya mengetahui metode apa untuk memanggil tidak jauh berbeda dari mengetahui simbol apa yang harus dipanggil dalam HQL (maksud saya, serius, kami tidak menyelesaikan PDE di sini.)
luis.espinal
Apakah ada contoh bagus yang menunjukkan mengapa HQL lebih baik daripada kriteria api dalam kasus tertentu? Saya membaca akhir dari satu blog, tetapi tidak mengerti apa-apa. Akan sangat menghargai jika Anda bisa membantu. Terima kasih. Tautan - javalobby.org/articles/hibernatequery102
Erran Morad
1
Kueri bernama HQL dikompilasi pada waktu penggunaan dan pada titik ini bidang yang hilang (mungkin untuk refaktor yang buruk?) Terdeteksi. Saya pikir ini membuat kode lebih tangguh dan sebenarnya lebih sedikit kesalahan daripada kriteria.
narduk
Isi-otomatis pada Kriteria tidak berguna karena sifat-sifatnya hanyalah string.
Lluis Martinez
35

Saya biasanya menggunakan Kriteria ketika saya tidak tahu input apa yang akan digunakan pada potongan data mana. Seperti pada formulir pencarian di mana pengguna dapat memasukkan 1 hingga 50 item dan saya tidak tahu apa yang akan mereka cari. Sangat mudah untuk hanya menambahkan lebih ke kriteria saat saya memeriksa apa yang dicari pengguna. Saya pikir akan sedikit lebih repot untuk menempatkan permintaan HQL dalam keadaan itu. HQL sangat bagus ketika saya tahu persis apa yang saya inginkan.

Arthur Thomas
sumber
1
Ini komentar yang bagus. Saat ini kami membuat string HQL yang sangat besar untuk formulir pencarian yang berisi banyak objek berbeda melalui gabungan. Terlihat jelek. Akan melihat apakah Kriteria dapat membersihkan itu. Menarik ...
cbmeeks
Terima kasih. Ini adalah contoh yang bagus. Bisakah Anda memberi saya lebih banyak?
Erran Morad
31

HQL jauh lebih mudah dibaca, lebih mudah untuk debug menggunakan alat-alat seperti plugin Eclipse Hibernate, dan lebih mudah untuk login. Kueri kriteria lebih baik untuk membangun kueri dinamis di mana banyak perilaku ditentukan saat runtime. Jika Anda tidak tahu SQL, saya bisa mengerti menggunakan kriteria Kriteria, tetapi secara keseluruhan saya lebih suka HQL jika saya tahu apa yang saya inginkan dimuka.

Brian Deterling
sumber
22

Kriteria adalah satu-satunya cara untuk menentukan pencarian kunci alami yang mengambil keuntungan dari optimasi khusus di cache kueri tingkat kedua. HQL tidak memiliki cara untuk menentukan petunjuk yang diperlukan.

Anda dapat menemukan lebih banyak info di sini:

Alex Miller
sumber
21

Kriteria Api adalah salah satu konsep Hibernate yang bagus. menurut pandangan saya ini adalah beberapa poin dimana kita dapat membuat perbedaan antara HQL dan Kriteria Api

  1. HQL adalah untuk melakukan operasi pilih dan non-pilih pada data, tetapi Kriteria hanya untuk memilih data, kami tidak dapat melakukan operasi non-pilih menggunakan kriteria.
  2. HQL cocok untuk mengeksekusi Kueri Statis, sedangkan Kriteria cocok untuk mengeksekusi Kueri Dinamis
  3. HQL tidak mendukung konsep pagination , tetapi kami dapat mencapai pagination dengan Kriteria.
  4. Kriteria digunakan untuk mengambil lebih banyak waktu untuk dieksekusi daripada HQL.
  5. Dengan Kriteria kami aman dengan SQL Injection karena pembuatan kueri yang dinamis tetapi dalam HQL karena kueri Anda diperbaiki atau dipisah-pisahkan, tidak ada aman dari SQL Injection
Arvind
sumber
11
Beberapa poin Pagination ada di HQL: Anda dapat menggunakan limit offset:rows Dalam hql Anda dapat menghindari injeksi sql menggunakansetParameter
Viswanath Lekshmanan
13

Untuk menggunakan yang terbaik dari kedua dunia, ekspresifitas dan keringkasan HQL dan sifat dinamis Kriteria pertimbangkan untuk menggunakan Querydsl .

Querydsl mendukung JPA / Hibernate, JDO, SQL dan Collections.

Saya adalah pengelola Querydsl, jadi jawaban ini bias.

Timo Westkämper
sumber
13

Bagi saya, Kriteria itu cukup mudah untuk Memahami dan membuat pertanyaan Dinamis. Tetapi kekurangan yang saya katakan sejauh ini adalah bahwa ia memuat semua banyak-satu dll hubungan karena kami hanya memiliki tiga jenis FetchModes yaitu Pilih, Proksi dan Default dan dalam semua kasus ini memuat banyak-satu (mungkin saya salah jika begitu membantu saya keluar :))

Masalah kedua dengan Kriteria adalah bahwa ia memuat objek lengkap yaitu jika saya ingin hanya memuat EmpName dari seorang karyawan, ia tidak akan muncul dengan insted ini muncul dengan objek Karyawan lengkap dan saya bisa mendapatkan EmpName dari itu karena ini benar-benar bekerja buruk di pelaporan . sedangkan HQL hanya memuat (tidak memuat asosiasi / hubungan) apa yang Anda inginkan sehingga meningkatkan kinerja berkali-kali.

Salah satu fitur dari Kriteria adalah bahwa ia akan aman dari SQL Injection karena pembuatan kueri yang dinamis di mana seperti dalam HQL sebagai permintaan Anda diperbaiki atau parameterisasi sehingga tidak aman dari SQL Injection.

Juga jika Anda menulis HQL di file aspx.cs Anda, maka Anda erat dengan ur DAL Anda.

Secara keseluruhan kesimpulan saya adalah bahwa ada tempat-tempat di mana Anda tidak dapat hidup tanpa HQL seperti laporan jadi gunakan yang lain Kriteria lebih mudah untuk dikelola.

Zafar
sumber
13
HQL BUKAN aman injeksi SQL
Varun Mehta
Saya pikir Kriteria tidak aman injeksi. Lihat posting saya di sini: stackoverflow.com/questions/6746486/…
Mister Smith
4
HQL IS sql aman injeksi dengan menambahkan 'setParameter'
Jelaskan
2
@Zafar: Anda hanya dapat memilih properti tertentu dari suatu entitas menggunakan proyeksi
Răzvan Flavius ​​Panda
@Zafar Anda dapat mengatur proyeksi dalam kriteria query untuk memilih kolom tertentu. Anda dapat mengambil EmpName, tidak perlu mengambil objek lengkap.
Khatri
12

API Kriteria

Kriteria API lebih cocok untuk permintaan yang dihasilkan secara dinamis. Jadi, jika Anda ingin menambahkan filter klausa WHERE, GABUNG klausa, atau ubah klausa ORDER BY atau kolom proyeksi, maka API Kriteria dapat membantu Anda membuat kueri secara dinamis dengan cara yang juga mencegah serangan SQL Injection .

Di sisi lain, kueri Kriteria kurang ekspresif dan bahkan dapat menyebabkan kueri SQL yang sangat rumit dan tidak efisien, seperti yang dijelaskan dalam artikel ini .

JPQL dan HQL

JPQL adalah bahasa permintaan entitas standar JPA sementara HQL memperluas JPQL dan menambahkan beberapa fitur khusus Hibernate.

JPQL dan HQL sangat ekspresif dan menyerupai SQL. Tidak seperti Kriteria API, JPQL dan HQL membuatnya mudah untuk memprediksi permintaan SQL yang mendasarinya yang dihasilkan oleh penyedia JPA. Juga jauh lebih mudah untuk meninjau kueri HQL seseorang daripada yang Kriteria.

Perlu dicatat bahwa memilih entitas dengan JPQL atau API Kriteria masuk akal jika Anda perlu memodifikasinya. Kalau tidak, proyeksi DTO adalah pilihan yang jauh lebih baik.

Kesimpulan

Jika Anda tidak perlu memvariasikan struktur kueri entitas, maka gunakan JPQL atau HQL. Jika Anda perlu mengubah kriteria pemfilteran atau pengurutan atau mengubah proyeksi, maka gunakan API Kriteria.

Namun, hanya karena Anda menggunakan JPA atau Hibernate, itu tidak berarti Anda tidak boleh menggunakan SQL asli. Permintaan SQL sangat berguna dan JPQL dan API Kriteria bukan pengganti untuk SQL. Lihat artikel ini untuk detail lebih lanjut tentang topik ini.

Vlad Mihalcea
sumber
11

Bagi saya, kemenangan terbesar pada Kriteria adalah API Contoh, di mana Anda dapat melewatkan objek dan hibernasi akan membangun kueri berdasarkan properti objek tersebut.

Selain itu, kriteria API memiliki keanehannya (saya percaya tim hibernate sedang mengerjakan ulang apinya), seperti:

  • a criteria.createAlias ​​("obj") memaksa gabungan dalam dan bukan gabungan luar yang mungkin
  • Anda tidak dapat membuat alias yang sama dua kali
  • beberapa klausa sql tidak memiliki kriteria rekanan sederhana (seperti subselect)
  • dll.

Saya cenderung menggunakan HQL ketika saya ingin kueri yang mirip dengan sql (hapus dari Pengguna di mana status = 'diblokir'), dan saya cenderung menggunakan kriteria ketika saya tidak ingin menggunakan penambahan string.

Keuntungan lain dari HQL adalah bahwa Anda dapat menentukan semua pertanyaan Anda sebelumnya, dan bahkan membuatnya menjadi file atau lebih.

Miguel Ping
sumber
9

Kriteria api menyediakan satu fitur berbeda yang tidak disediakan oleh SQL atau HQL. yaitu. memungkinkan kompilasi memeriksa waktu permintaan.

pengguna1165443
sumber
7

Kami menggunakan sebagian besar Kriteria dalam aplikasi kami di awal tetapi setelah itu diganti dengan HQL karena masalah kinerja.
Terutama kami menggunakan kueri yang sangat kompleks dengan beberapa gabungan yang mengarah ke beberapa kueri dalam Kriteria tetapi sangat dioptimalkan dalam HQL.
Kasusnya adalah bahwa kita hanya menggunakan beberapa properti pada objek tertentu dan bukan objek lengkap. Dengan Kriteria masalah juga merangkai tali.
Katakanlah jika Anda perlu menampilkan nama dan nama pengguna di HQL itu cukup mudah (name || ' ' || surname)tetapi di Crteria ini tidak mungkin.
Untuk mengatasi ini kami menggunakan ResultTransormers, di mana ada metode di mana rangkaian tersebut diimplementasikan untuk hasil yang diperlukan.
Hari ini kami terutama menggunakan HQL seperti ini:

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

jadi dalam kasus kami catatan yang dikembalikan adalah peta properti yang dibutuhkan.

Bojan Kraut
sumber
1
Dengan Kriteria, Anda dapat menggunakan org.hibernate.criterion.CriteriaSpecification.ALIAS_TO_ENTITY_MAP
AA.
Mengembalikan daftar peta dalam pengalaman saya memiliki kinerja yang sangat buruk. Saya lebih suka mengembalikan daftar array objek atau daftar kacang (Anda selalu dapat mendefinisikan kacang yang sesuai dengan set hasil spesifik Anda).
Lluis Martinez
7
  • HQL adalah untuk melakukan operasi pilih dan non-pilih pada data, tetapi Kriteria hanya untuk memilih data, kami tidak dapat melakukan operasi non-pilih menggunakan kriteria
  • HQL cocok untuk mengeksekusi Kueri Statis, sedangkan Kriteria cocok untuk mengeksekusi Kueri Dinamis
  • HQL tidak mendukung konsep pagination, tetapi kami dapat mencapai pagination dengan Kriteria
  • Kriteria digunakan untuk mengambil lebih banyak waktu untuk mengeksekusi kemudian HQL
  • Dengan Kriteria kami aman dengan SQL Injection karena pembuatan kueri yang dinamis tetapi dalam HQL karena kueri Anda ditetapkan atau dipisah-pisahkan, tidak ada aman dari SQL Injection.

sumber

Premraj
sumber
Untuk memperjelas, kueri kriteria menggunakan API Kriteria Hibernate mungkin tersedia untuk kueri, tetapi kriteria JPA kueri mencakup pemilihan, pembaruan, dan penghapusan. Lihat CriteriaUpdate<T>dan CriteriaDelete<T>untuk referensi.
Naros
5

Kriteria kueri untuk secara dinamis kita dapat membuat kueri berdasarkan input kita .. Dalam kasus permintaan Hql adalah permintaan statis setelah kita membuat kita tidak dapat mengubah struktur kueri.

pengguna1679378
sumber
2
Tidak begitu. Dengan HQL Anda dapat mengatur properti dengan pengidentifikasi ':', dan kemudian mengganti properti tersebut dengan nilai unik. Misalnya, Permintaan q = session.createQuery ("SELECT: aValue FROM my_table"); dan kemudian q.setParameter ("aValue", "some_column_name");
MattC
@MattC Dalam contoh Anda, Anda mengubah nilai parameter, bukan struktur kueri.
Tsar
4

Saya tidak ingin menendang kuda mati di sini, tetapi penting untuk menyebutkan bahwa kriteria Kriteria sekarang sudah tidak digunakan lagi. Gunakan HQL.

Eskir
sumber
1

Saya juga lebih suka Kueri Kriteria untuk kueri dinamis. Tapi saya lebih suka hql untuk menghapus kueri, misalnya jika menghapus semua catatan dari tabel anak untuk induk id 'xyz', itu mudah dicapai oleh HQL, tetapi untuk kriteria API pertama kita harus mem-burn n jumlah permintaan penghapusan di mana n adalah jumlah anak catatan tabel.

Punit Patel
sumber
0

Sebagian besar jawaban di sini menyesatkan dan menyebutkan bahwa Criteria Querieslebih lambat daripada HQL, yang sebenarnya tidak demikian.

Jika Anda mempelajari lebih dalam dan melakukan beberapa tes, Anda akan melihat Kriteria Query berkinerja lebih baik daripada HQL biasa .

Dan juga dengan Kriteria Kueri Anda mendapatkan kontrol Berorientasi Objek yang tidak ada dengan HQL .

Untuk informasi lebih lanjut, baca jawaban ini di sini .

Pritam Banerjee
sumber
0

Ada cara lain. Saya akhirnya dengan membuat parser HQL berdasarkan sintaks asli hibernate sehingga pertama mem-parsing HQL maka bisa secara dinamis menyuntikkan parameter dinamis atau secara otomatis menambahkan beberapa filter umum untuk permintaan HQL. Ini sangat bagus!

Wallace Peng
sumber
0

Posting ini cukup lama. Sebagian besar jawaban berbicara tentang kriteria Hibernate, bukan kriteria JPA. JPA 2.1 menambahkan CriteriaDelete / CriteriaUpdate, dan EntityGraph yang mengontrol apa yang harus diambil. API Kriteria lebih baik karena Java adalah OO. Itu sebabnya JPA dibuat. Ketika JPQL dikompilasi, itu akan diterjemahkan ke pohon AST (model OO) sebelum diterjemahkan ke SQL.

Hari yang cerah
sumber
-3

HQL dapat menyebabkan masalah keamanan seperti injeksi SQL.

Emad Aghayi
sumber
11
Masalah-masalah ini bukan disebabkan oleh HQL, tetapi oleh kurangnya pemahaman tentang praktik pengembangan perangkat lunak dasar. Saya dapat membuat kode rentan terhadap serangan injeksi sql dengan kriteria api juga.
Jens Schauder
1
Ini seperti mengatakan "meminta RDBMS dari Jawa dapat menyebabkan masalah keamanan injeksi SQL": D
Czar