1. Kueri Objek Entitas
Kueri Objek Entitas adalah dasar dari kueri HQL. Sebagai bahasa kueri objek, ini berbeda dari SQL selama operasi kueri. Konten dalam string kueri harus diganti dengan nama kelas dan nama atribut kelas. Metode kueri ini relatif sederhana. Selama Anda memiliki keterampilan SQL, sangat mudah untuk menggunakan HQL. Namun, ada beberapa masalah yang perlu diperhatikan, yaitu, meminta dan mendapatkan data bukanlah tujuannya, dan yang perlu dipertimbangkan adalah bagaimana menulis pernyataan kueri yang efisien, yang merupakan fokus diskusi.
1.N+1 Masalah
(1) Apa masalah N+1
Ketika saya pertama kali mendengar kata benda ini, saya mungkin memiliki keraguan. Saya belum pernah mendengar masalah N+1 sebelumnya. Jadi apa artinya? N+1 mengacu pada data N dalam tabel, jadi ketika mendapatkan data N ini, perintah N+1 SQL akan dihasilkan. Operasi ini disebut n+1. Di sini, 1 mengacu pada mengeluarkan pernyataan yang mencari daftar ID, dan N mengacu pada mengeluarkan pernyataan SQL berdasarkan ID untuk memuat objek terkait. Operasi kueri semacam ini sangat tidak efisien dan sering dihasilkan dalam iterator. Dengan kata lain, jika kita secara langsung mengubah hasil kueri menjadi iterator, masalah ini akan terjadi, sebagai berikut:
public void testQuery () {session session = null; coba {session = hibernateutils.getSession (); session.begintransaction (); /*** Akan ada masalah n+1. Nilai yang disebut N+1 adalah mengeluarkan pernyataan N+1 SQL** 1: mengeluarkan pernyataan yang menanyakan daftar ID** n: masalah n pernyataan SQL berdasarkan ID dan memuat objek yang relevan*/ iterator iter = session.createquery ("dari siswa"). Iterate (); while (iter.hasnext ()) {student student = (student) iter.next (); System.out.println (student.getName ()); } session.getTransaction (). commit (); } catch (Exception e) {E.PrintStackTrace (); session.getTransaction (). rollback (); } akhirnya {hibernateutils.closesession (sesi); }}Kode kueri di atas akan menyebabkan masalah n+1, karena kueri dikembalikan sebagai iterator, sehingga pernyataan SQL akan dikeluarkan jika tidak dihasilkan sekali. Ini terutama tergantung pada mekanisme kueri iterator, yang meminta data dari cache. Jika data tidak ada di cache, data akan dikonversi menjadi memori terlebih dahulu, sehingga pernyataan SQL Query akan dikeluarkan saat ini, sehingga pernyataan SQL akan dihasilkan setiap iterasi. Metode penulisan ini sebenarnya merupakan kesalahan dan dapat diselesaikan dengan menggunakan metode lain untuk mengoptimalkan.
(2) Hindari masalah n+1
Masalah n+1 terjadi karena penggunaan iterate yang tidak tepat. Tentu saja, metode lain dapat digunakan untuk menghindari masalah N+1 ini. Berikut adalah metode daftar. Perbedaan terbesar antara daftar dan iterate adalah bahwa daftar memasukkan data ke dalam cache, tetapi tidak menggunakan cache. Secara default, daftar akan mengeluarkan pernyataan SQL setiap saat. Sebelum menggunakan Itererate, Anda dapat menggunakan daftar untuk menyimpan data ke database, sehingga Iterate dapat membaca dari cache saat mengakses data, menghindari terjadinya masalah N+1. Kodenya adalah sebagai berikut:
public void testQuery () {session session = null; coba {session = hibernateutils.getSession (); session.begintransaction (); Daftar Siswa = session.createQuery ("From Student"). Daftar (); System.out.println ("----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Maka tidak ada pernyataan SQL yang didasarkan pada ID yang dikeluarkan, dan data dalam cache secara langsung digunakan * * mengulangi metode jika data ada dalam cache, itu dapat meningkatkan kinerja, jika tidak masalah n +1 akan terjadi */ // Anda dapat menggunakan siswa (iteror) (siswa). System.out.println (Student.getName ()); }}Contoh di atas menghindari masalah n+1, karena setelah melakukan operasi daftar, data akan ditempatkan di cache sesi (cache tingkat pertama). Oleh karena itu, saat menggunakan iterate, pernyataan akan dikeluarkan untuk menanyakan daftar ID, dan kemudian data yang sesuai akan dimuat dalam cache sesuai dengan ID. Jika ada data yang cocok dengan cache, kueri pernyataan SQL berdasarkan ID tidak akan lagi dikeluarkan, dan data dalam cache akan langsung digunakan. Metode iterate dapat meningkatkan kinerja jika data ada di cache, jika tidak masalah n +1 akan terjadi.
2. Kueri Navigasi Objek
Navigasi objek mengacu pada mendapatkan data dari objek lain sesuai dengan navigasi atribut objek dalam satu objek. Ini dapat menyederhanakan pernyataan kueri dan mengoptimalkan metode kueri. Jika kita mengikuti ide -ide biasa kita, kita dapat menulis ulang dan menulis objek kelas lain untuk mendapatkan operasi objek lain, yang lebih rumit untuk membandingkan pernyataan navigasi objek.
@SuppressWarnings ({"Uncecked", "RawTypes"}) public void testQuery1 () {session session = null; coba {session = hibernateutils.getSession (); session.begintransaction (); // Kembalikan daftar Atribut Set Hasil, jenis elemen dan jenis atribut di kelas entitas adalah daftar yang sama siswa = sesi. untuk (iterator item = student.iterator (); ite.hasnext ();) {student obj = (siswa) ite.next (); System.out.println (obj.getName ()); } session.getTransaction (). commit (); } catch (Exception e) {E.PrintStackTrace (); session.getTransaction (). rollback (); } akhirnya {hibernateutils.closesession (sesi); }}Pernyataan kueri dalam contoh di atas menggunakan metode navigasi objek. Pernyataan kueri adalah permintaan informasi dari objek siswa, tetapi atribut objek yang akan dibandingkan berasal dari atribut nama objek kelas. Pada saat ini, menggunakan metode permintaan navigasi objek akan secara signifikan meningkatkan efisiensi kueri dan mengoptimalkan pernyataan kueri. Jika itu adalah metode kueri biasa, sejumlah besar pernyataan koneksi dapat dihasilkan, yang sangat rumit.
2. Kueri Asli SQL
Nilai kueri asli adalah menggunakan pernyataan SQL untuk meminta dan mendapatkan data, daripada menggunakan pernyataan HQL. Metode penggunaannya sebenarnya sangat sederhana, mirip dengan HQL. Anda hanya perlu menggunakan metode CreateSqlQuery untuk meminta. Ini sebenarnya mirip dengan metode createqueer HQL. Kodenya adalah sebagai berikut:
public void testqeury () {session session = null; coba {session = hibernateutils.getSession (); session.begintransaction (); Daftar Daftar = session.createSqlQuery ("Pilih * dari t_student"). Daftar (); untuk (iterator item = list.iterator (); ite.hasnext ();) {objek [] obj = (objek []) ite.next (); System.out.println (obj [0]+","+obj [1]); } session.getTransaction (). commit (); } catch (Exception e) {E.PrintStackTrace (); session.getTransaction (). rollback (); } akhirnya {hibernateutils.closesession (sesi); }}Kode di atas menggunakan metode CreateSQlQuery. String kueri dalam metode ini adalah pernyataan SQL. Ini mengimplementasikan metode kueri string yang mendasarinya. Perbedaannya adalah bahwa HQL memiliki lapisan pengemasan lain, dan mengkonfigurasi opsi dialek yang sesuai di hibernate.cfg.xml untuk menyelesaikan pemetaan.
3. Kueri Koneksi
Kueri koneksi sering digunakan dalam SQL untuk mendapatkan kumpulan beberapa objek. Di antara mereka, yang paling umum digunakan adalah gabungan dalam, bergabung kiri, gabungan kanan, dll., Yang merujuk pada kueri gabungan dalam, kueri gabungan luar kiri, dan kueri gabungan luar kanan. Konten yang mereka kembalikan selama kueri adalah produk Cartesian antara entitas, konten kueri dan beberapa konten dari tabel kiri, konten kueri dan beberapa konten tabel kanan, dan fungsi kueri sangat kuat. Metode kueri koneksi HQL dan kueri koneksi SQL sama dalam hasil kueri, tetapi ada sedikit perbedaan dalam pernyataan kueri.
1. Koneksi batin
Kueri Intrajoin dari HQL dapat ditanyai menggunakan Pernyataan Join Dalam atau Pernyataan Join, dan set hasil yang diperoleh adalah produk Cartesian. Mirip dengan kueri intra-koneksi SQL, kueri gabungan HQL dibagi menjadi dua jenis: eksplisit dan implisit. Kueri yang ditampilkan mengacu pada kata kunci gabungan di string kueri. Kueri implisit tidak perlu menambahkan gabungan di string.
// koneksi dalam @suppresswarnings ({"tidak dicentang", "rawtypes"}) public void testQuery () {session session = null; coba {session = hibernateutils.getSession (); session.begintransaction (); // Kembalikan daftar Atribut Set Hasil, jenis elemen dan jenis atribut di kelas entitas adalah daftar yang sama siswa = session.createqueery ("pilih s.name, c.name dari siswa S goin s.classes c"). List (); untuk (iterator item = student.iterator (); ite.hasnext ();) {objek [] obj = (objek []) ite.next (); System.out.println (OBJ [0]); } session.getTransaction (). commit (); } catch (Exception e) {E.PrintStackTrace (); session.getTransaction (). rollback (); } akhirnya {hibernateutils.closesession (sesi); }}
2. Koneksi eksternal
Koneksi eksternal dibagi menjadi koneksi luar kiri dan kueri koneksi luar kanan. Metode kueri serupa, tetapi hasil kueri berbeda. Mereka sama dengan koneksi eksternal SQL dalam hasil kueri. Perbedaannya adalah metode penulisan. Kode spesifiknya adalah sebagai berikut:
@SuppressWarnings ({"Uncecked", "RawTypes"}) public void testQuery () {session session = null; coba {session = hibernateutils.getSession (); session.begintransaction (); // Kembalikan daftar Atribut Set Hasil, jenis elemen dan jenis atribut di kelas entitas adalah daftar yang sama siswa = session.createqueery ("Pilih S.Name, c.name dari Siswa S Left Join S.Classes C"). Daftar (); untuk (iterator item = student.iterator (); ite.hasnext ();) {objek [] obj = (objek []) ite.next (); System.out.println (OBJ [0]); } session.getTransaction (). commit (); } catch (Exception e) {E.PrintStackTrace (); session.getTransaction (). rollback (); } akhirnya {hibernateutils.closesession (sesi); }}Kode di atas menggunakan pernyataan kueri gabungan luar kiri. Metode kueri gabungan luar kanan yang sesuai mirip dengan gabungan luar kiri. Konversi saja kiri ke kanan. Data kueri disimpan dalam objek daftar, dan konten kueri dapat diperoleh melalui daftar.
4. Kueri Penamaan Eksternal
Kueri bernama eksternal mengacu pada penulisan pernyataan kueri ke dalam file pemetaan dan menggunakan tag <duery> untuk menentukan pernyataan HQL dalam file pemetaan. Dengan cara ini, pernyataan HQL yang ditentukan dapat mewujudkan fungsi konfigurasi fungsi. Jika ada masalah, hanya perlu memodifikasi konfigurasi. Jika Anda ingin menggunakan pernyataan SQL ini, Anda dapat menggunakan metode session.getNamedQuery () dalam program untuk mendapatkan string kueri HQL, seperti yang ditunjukkan pada contoh berikut.
1. Pernyataan kueri eksternal
Contoh berikut menunjukkan aplikasi pernyataan kueri eksternal, tambahkan tag <puery> ke file pemetaan, tambahkan atribut nama ke tag, dan tambahkan string ke <! [Cdata []]>, sehingga string kueri yang sesuai dapat diperoleh dalam program sesuai dengan atribut nama kueri.
<? Xml Version = "1.0"?> <! Doctype hibernate-mapping public "-// hibernate/hibernate pemetaan dtd 3.0 // en" "http://hibernate.sourceForge.net/hibernate-papping-3.0.dtd"> <hibernate-papping> <"cooming." table="t_student"> <id name="id"> <generator//id> <property name="name"/> <property name="createTime"></property> <!-- Add a new Classes column to the Student on one side, and the column name should be the same as the List of Classes.hbm.xml --> <many-to-one name="classes" column="classesid"></many-to-one> </class> <query name = "querystudent"> <! [cdata [pilih s dari siswa di mana s.id <? ]]> </query> </hibernate-Mapping>
Kueri bernama eksternal menempatkan pernyataan kueri di file pemetaan, sehingga dapat dianggap sebagai string kueri publik. Ini adalah keuntungannya, sehingga file program lain dapat diperoleh dan digunakan. Selain itu, ini meningkatkan kenyamanan modifikasi sebagai string publik.
2. Aplikasi Program
Setelah mendefinisikan pernyataan kueri eksternal, perlu menggunakannya dalam program. HQL menyediakan metode getNameQuery untuk mendapatkan string pernyataan kueri eksternal. Nama kursor eksternal perlu ditambahkan ke metode ini. HQL akan meminta blok pernyataan SQL yang sesuai berdasarkan nama kursor, sebagai berikut:
// kueri penamaan eksternal @suppresswarnings ({"uncecked", "rawTypes"}) public void testQuery () {session session = null; coba {session = hibernateutils.getSession (); session.begintransaction (); Daftar siswa = session.getNamedQuery ("querystudent"). SetParameter (0, 10) .list (); untuk (iterator item = student.ite.hasnext ();) {student obj = (siswa) ite.next (); System.out.println (obj.getName ()); } session.getTransaction (). commit (); } catch (Exception e) {E.PrintStackTrace (); session.getTransaction (). rollback (); } akhirnya {hibernateutils.closesession (sesi); }}