Artikel ini menjelaskan teknologi pemuatan latensi hibernasi. Bagikan untuk referensi Anda, sebagai berikut:
Pemuatan malas Hibernae adalah teknik yang sangat umum. Atribut pengumpulan entitas akan ditunda secara default, dan entitas yang terkait dengan entitas juga akan ditunda secara default. Hibernate menggunakan pemuatan yang tertunda ini untuk mengurangi overhead memori sistem, sehingga memastikan kinerja operasi hibernate.
Pertama -tama mari kita menganalisis "rahasia" pemuatan penundaan hibernasi.
Pemuatan Malas Properti Koleksi
Ketika Hibernate menginisialisasi entitas persisten dari database, apakah atribut koleksi dari entitas yang diinisialisasi dengan kelas persisten? Jika atribut koleksi berisi 100.000 atau bahkan jutaan catatan, merangkak semua atribut koleksi sambil menginisialisasi entitas yang persisten akan menghasilkan penurunan kinerja yang tajam. Sangat mungkin bahwa sistem hanya perlu menggunakan beberapa catatan dalam atribut koleksi kelas persisten, dan tidak semua atribut koleksi sama sekali. Dengan cara ini, tidak perlu memuat semua atribut koleksi sekaligus.
Strategi pemuatan malas umumnya direkomendasikan untuk properti pengumpulan. Yang disebut pemuatan tertunda adalah memuat data terkait dari database ketika sistem perlu menggunakan atribut pengumpulan.
Misalnya, kelas orang berikut memiliki atribut koleksi, dan elemen dalam atribut koleksi memiliki alamat jenis, dan potongan kode dari kelas orang adalah sebagai berikut:
Daftar 1. Person.java
orang kelas publik {// Identifikasi Atribut Private Integer ID; // Nama Orang Atribut Nama String Pribadi; // Pertahankan usia orang Atribut Privat usia; // Gunakan set untuk menyimpan atribut koleksi Atribut Private Set <dressing> Alamat = HashSet baru <Adamat> (); // Metode setter dan getter dari setiap atribut dihilangkan di bawah ...}Agar Hibernate mengelola properti pengumpulan kelas persisten, program ini menyediakan file pemetaan berikut untuk kelas persisten:
Listing 2. Person.hbm.xml
<? XML Versi = "1.0" encoding = "gbk"?> <! Doctype hibernate-mapping public "-// hibernate/hibernate pemetaan dtd 3.0 // en" "http://www.hibernate.org/dtd/hibernate-papping-3.0.dtde"> <hibernate.org/dtd package="org.crazyit.app.domain"><!-- Mapping Person Persistence Class--><class name="Person" table="person_inf"><!-- Mapping Identification Property ID --><id name="id" column="person_id"><!-- Define primary key generator policy --><generator/><!-- Used to map common attributes --><property name="name" type="string"/><property name = "usia" type = "int"/> <!-atribut koleksi peta-> <set name = "alamat" table = "person_address" lazy = "true"> <!-tentukan kolom kunci asing terkait-> <Key column = "person_id"/> <composite-element> <!-peta normal detail atribut normal-> <property name = "detail" name = "zip"/> </composite-element> </tion> </belas> </hibernate-Mapping>
Dari kode di atas yang memetakan file, kita dapat melihat bahwa kelas alamat dalam atribut koleksi orang hanyalah pojo normal. Kelas alamat berisi dua atribut: detail dan zip. Karena kode kelas alamat sangat sederhana, kode untuk kelas ini tidak lagi diberikan di sini.
Kode dalam elemen <set .../> dalam file pemetaan di atas menentukan malas = "true" (untuk <set .../> elemen, malas = "true" adalah nilai default), yang menentukan bahwa hibernate akan menunda memuat objek alamat dalam atribut koleksi.
Misalnya, muat entitas orang dengan ID 1 dengan mengikuti kode berikut:
Sesi sesi = sf.getCurrentSession (); transaksi tx = session.begintransaction (); orang p = (orang) session.get (person.class, 1); // <1> System.out.println (p.getName ());
Kode di atas hanya perlu mengakses entitas orang dengan ID 1, dan tidak ingin mengakses objek alamat yang terkait dengan entitas orang ini. Ada dua situasi saat ini:
1. Jika pemuatan tidak tertunda, Hibernate akan segera mengambil objek alamat yang terkait dengan entitas orang saat memuat catatan data yang sesuai dengan entitas orang.
2. Jika pemuatan malas digunakan, Hibernate hanya akan memuat catatan data yang sesuai dengan entitas orang.
Jelas bahwa pendekatan kedua tidak hanya mengurangi interaksi dengan database, tetapi juga menghindari overhead memori yang disebabkan oleh entitas alamat pemuatan - ini juga mengapa Hibernate memungkinkan pemuatan malas secara default.
Pertanyaannya sekarang adalah, bagaimana pemuatan malas diimplementasikan? Hibernate apa alamat nilai properti entitas orang saat memuat entitas seseorang?
Untuk mengatasi masalah ini, kami menetapkan breakpoint pada kode <1> dan men -debug di Eclipse. Pada saat ini, kita dapat melihat bahwa jendela Eclipse Console memiliki output seperti yang ditunjukkan pada Gambar 1:
Gambar 1. Output konsol untuk properti pengumpulan pemuatan malas
Seperti yang ditunjukkan pada output pada Gambar 1, Hibernate hanya mengambil data dari tabel data yang sesuai dengan entitas orang, dan tidak mengambil data dari tabel data yang sesuai dengan objek alamat. Ini malas memuat.
Jadi apa alamat properti entitas orang? Pada saat ini, Anda dapat melihat hasil yang ditunjukkan pada Gambar 2 dari jendela Variabel Eclipse:
Gambar 2. Nilai atribut koleksi malas yang dimuat
Dari konten dalam kotak pada Gambar 2, dapat dilihat bahwa properti alamat bukan kelas implementasi yang akrab seperti hashset dan treeset, tetapi kelas implementasi persistentset, yang merupakan kelas implementasi yang disediakan oleh Hibernate untuk antarmuka yang ditetapkan.
Objek pengumpulan persistentset tidak benar -benar menangkap data tabel data yang mendasarinya, sehingga secara alami tidak mungkin untuk benar -benar menginisialisasi objek alamat dalam koleksi. Namun, Koleksi PersistentSet memiliki atribut sesi, yang merupakan sesi hibernasi. Ketika program perlu mengakses elemen pengumpulan persistentset, persistentset akan menggunakan atribut sesi ini untuk mengambil catatan data yang sesuai dengan objek alamat aktual.
Jadi apa sebenarnya yang Anda ambil catatan data yang sesuai dengan entitas alamat tersebut? Ini tidak sulit untuk persistentset, karena ada juga atribut pemilik dalam koleksi persistentset, yang menunjukkan entitas orang yang dimiliki oleh objek alamat. Hibernate akan mencari data dari tabel data yang sesuai dengan alamat yang sesuai dengan tabel data.
Misalnya, kami mengklik baris alamat di jendela yang ditunjukkan pada Gambar 2, yang berarti kami memberi tahu Eclipse untuk men -debug dan mengeluarkan atribut alamat. Ini untuk mengakses atribut alamat. Saat ini, Anda dapat melihat pernyataan SQL berikut di jendela Eclipse Console:
Pilih alamat0_.person_id sebagai person1_0_0_, addresses0_.detail sebagai detail0_, addresses0_.zip sebagai zip0_from person_address address0_where address0_.person_id =?
Ini adalah Koleksi PersistentSet dan pernyataan SQL yang menangkap catatan alamat tertentu sesuai dengan atribut pemilik. Pada saat ini, Anda dapat melihat output yang ditunjukkan pada Gambar 3 dari jendela Variabel Eclipse:
Gambar 3. Nilai atribut koleksi yang dimuat
Seperti dapat dilihat dari Gambar 3, atribut alamat saat ini telah diinisialisasi, dan set berisi 2 objek alamat, yang merupakan dua objek alamat yang terkait dengan entitas orang.
Dari pengantar di atas, kita dapat melihat bahwa kunci untuk menunda pemuatan atribut hibernate terletak di kelas implementasi persistentset. Selama pemuatan malas, koleksi PersistentSet tidak memiliki elemen apa pun. Namun, persistentset akan mengadakan sesi hibernasi, yang dapat memastikan bahwa ketika program perlu mengakses pengumpulan, catatan data dimuat "segera" dan memuat elemen pengumpulan.
Mirip dengan Kelas Implementasi PersistentSet, Hibernate juga menyediakan PersistentList, PersistentMap, PersistentSortedMap, PersistentSortedSet dan kelas implementasi lainnya, dan fungsinya kira -kira mirip dengan persistentset.
Pembaca yang akrab dengan atribut koleksi hibernate harus diingat: Hibernate mensyaratkan bahwa atribut koleksi hanya dapat digunakan dengan antarmuka seperti set, daftar, peta, sortedset, sortedmap, dll., Dan tidak dapat diimplementasikan menggunakan hashset, arraylist, hashmap, treeset, tregaap dan kelas implementasi lainnya. Alasannya adalah bahwa Hibernate perlu menunda pemuatan atribut koleksi, dan penundaan pemuatan hibernate bergantung pada persistentset, persistentlist, persistentMap, persistentsortedMap, dan persistentsortedset untuk menyelesaikan - yaitu, pengembangan yang mendasari pengembangan untuk menggunakan classmace dan daripada classmate dan daripada classmate dan daripada collecder dan daripada collecder dan daripada collecpements dan daripada collecder dan bukannya collements dan daripada collecder class dan daripada LAZY LOADING, DECLARY.
Hibernate menggunakan pemuatan malas untuk atribut koleksi secara default. Dalam beberapa kasus khusus, atur atribut lazy = "false" untuk elemen seperti <set .../>, <daftar .../>, <peta .../> untuk membatalkan pemuatan malas.
Menunda pemuatan entitas terkait
Secara default, Hibernate juga akan menggunakan pemuatan malas untuk memuat entitas yang terkait. Apakah itu asosiasi satu-ke-banyak, asosiasi satu-ke-satu, atau asosiasi banyak-ke-banyak, Hibernate akan menggunakan pemuatan malas secara default.
Untuk entitas terkait, mereka dapat dibagi menjadi dua kasus:
1. Ketika entitas yang terkait adalah banyak entitas (termasuk satu-ke-banyak, banyak-ke-banyak): pada saat ini, entitas terkait akan ada dalam bentuk koleksi, dan hibernate akan menggunakan persistentset, persistentlist, persistentmap, persistentsortedmap, persistentsEtedset dan koleksi lainnya untuk mengelola entitas pemuatan malas. Ini adalah situasi yang diperkenalkan sebelumnya.
2. Ketika entitas terkait adalah entitas tunggal (termasuk satu-ke-satu dan banyak-ke-satu): Ketika hibernasi memuat entitas, entitas terkait yang tertunda akan menjadi objek proxy yang dihasilkan secara dinamis.
Ketika entitas yang terkait adalah entitas tunggal, yaitu, ketika entitas terkait dipetakan menggunakan <banyak-ke-satu .../> atau <satu-ke-satu .../>, kedua elemen ini juga dapat menentukan pemuatan malas melalui atribut malas.
Contoh berikut juga memetakan kelas alamat ke kelas persisten. Pada saat ini, kelas alamat juga menjadi kelas entitas, dan entitas orang dan entitas alamat membentuk asosiasi dua arah satu-ke-banyak. Kode file pemetaan saat ini adalah sebagai berikut:
Listing 3. Person.hbm.xml
<? XML Versi = "1.0" encoding = "gbk"?> <!-Tentukan informasi DTD untuk hibernate-> <! Doctype hibernate-mapping public "-// hibernate/hibernate hibernate dtd 3.0 // en" "http://www.hibernate.orgerg/papping." package="org.crazyit.app.domain"><!-- Mapping Person Persistence Class--><class name="Person" table="person_inf"><!-- Mapping Identification Property ID --><id name="id" column="person_id"><!-- Define primary key generator policy --><generator/><!-- Used to map common attributes --><property name="name" type="string"/><property name = "usia" type = "int"/> <!-atribut koleksi peta, elemen koleksi adalah entitas persisten lainnya yang tidak menentukan atribut kaskade, tentukan bahwa hubungan asosiasi tidak dikendalikan-> <set name = "alamat" inverse = "true"> <!-Tentukan kolom kunci asing yang terkait-> <Kolom Kunci = "orang_id"/<! -> <One-to-Many/> </set> </slement> <!-alamat peta kelas persisten-> <class name = "address" table = "address_inf"> <!-peta identifikasi atribut addressId-> <id name = "addressid" column = "address_id"> <!-Tentukan kebijakan generator kunci primer-<generator/</id </id> peta =!-peta norma norma norma norma nice generator utama-> <generator/id </id> <! Atribut zip-> <name properti = "zip"/> <!-Nama kolom harus ditentukan sebagai person_id, yang sama dengan nilai atribut kolom dari elemen kunci dalam entitas terkait-> <banyak-ke-satu nama = "person" column = "person_id" not-null = "true"/> </class> </hibernate-mapping>
Selanjutnya, program memuat entitas orang dengan ID 1 melalui cuplikan kode berikut:
// buka sesi sesi yang bergantung pada konteks = sf.getCurrentSession (); transaksi tx = session.begintransaction (); alamat alamat = (alamat) session.get (address.class, 1); // <1> System.out.println (address.getDetail ());
Untuk melihat pemrosesan entitas terkait Hibernate saat memuat entitas alamat, kami menetapkan breakpoint pada kode <1> dan men -debug di Eclipse. Pada saat ini, kita dapat melihat bahwa jendela konsol Eclipse mengeluarkan pernyataan SQL berikut:
Pilih address0_.address_id as address1_1_0_, address0_.detail sebagai detail1_0_, address0_.zip sebagai zip1_0_, address0_.person_id sebagai person4_1_0_ dari address_inf address0_where address0_.address_id =?
Tidak sulit untuk melihat dari pernyataan SQL ini bahwa Hibernate memuat tabel data yang sesuai dengan entitas alamat untuk merangkak catatan, tetapi tidak merangkak catatan dari tabel data yang sesuai dengan entitas orang, yaitu pemuatan malas berperan.
Dari jendela Variabel Eclipse, lihat output yang ditunjukkan pada Gambar 4:
Gambar 4. Entitas pemuatan yang tertunda
Dapat dilihat dengan jelas dari Gambar 4 bahwa entitas orang yang terkait dengan entitas alamat bukan objek orang, tetapi contoh dari orang tersebut _ $$ _ kelas javassist_0. Kelas ini adalah kelas proksi yang dihasilkan secara dinamis oleh Hibernate menggunakan Proyek Javassist. Ketika hibernate menunda memuat entitas yang terkait, Javassist akan digunakan untuk menghasilkan objek proxy dinamis, dan objek proxy ini akan bertanggung jawab untuk memproksi "belum dimuat".
Selama aplikasi perlu menggunakan entitas terkait yang "belum dimuat", orang _ $$ _ objek proxy javassist_0 akan bertanggung jawab untuk memuat entitas terkait yang sebenarnya dan mengembalikan entitas terkait yang sebenarnya - ini adalah pola proxy yang paling khas.
Klik atribut orang di jendela Variabel yang ditunjukkan pada Gambar 4 (yaitu, paksa atribut orang untuk digunakan dalam mode debug), dan kemudian Anda akan melihat output pernyataan SQL berikut di jendela konsol Eclipse:
Pilih Person0_.PERSON_ID sebagai orang1_0_0_, person0_.name as name0_0_, person0_.age as Age0_0_ dari person_inf person0_ di mana person0_.person_id =?
Pernyataan SQL di atas adalah pernyataan yang menangkap entitas terkait "penundaan pemuatan". Pada saat ini, Anda dapat melihat hasil yang ditunjukkan pada Gambar 5 dari output jendela variabel:
Gambar 5. Entitas yang dimuat
Hibernate mengadopsi mode "beban yang tertunda" untuk mengelola entitas terkait. Bahkan, ketika memuat entitas utama, itu tidak benar -benar mengambil data yang sesuai dari entitas yang terkait, tetapi hanya secara dinamis menghasilkan objek sebagai proksi entitas terkait. Ketika aplikasi benar -benar perlu menggunakan entitas terkait, objek proxy bertanggung jawab untuk mengambil catatan dari database yang mendasarinya dan menginisialisasi entitas yang terkait nyata.
Dalam pemuatan hibernate penundaan, apa yang mulai didapat oleh program klien adalah objek proxy yang dihasilkan secara dinamis, sedangkan entitas nyata didelegasikan ke objek proxy untuk manajemen - ini adalah pola proxy yang khas.
Mode agen
Mode proxy adalah mode desain dengan aplikasi yang sangat luas. Ketika kode klien perlu memanggil objek, klien sebenarnya tidak peduli apakah akan mendapatkan objek secara akurat. Hanya membutuhkan objek yang dapat menyediakan fungsi. Pada saat ini, kita dapat mengembalikan proxy (proxy) objek.
Dalam metode desain ini, sistem akan memberikan objek dengan objek proxy, dan objek proxy mengontrol referensi ke objek sumber. Proxy adalah objek Java yang bertindak atas nama objek Java lainnya. Dalam beberapa kasus, kode klien tidak ingin atau tidak dapat secara langsung memanggil callee, dan objek proxy dapat bertindak sebagai perantara antara klien dan objek target.
Untuk klien, ia tidak dapat membedakan perbedaan antara objek proxy dan objek nyata, juga tidak perlu membedakan perbedaan antara objek proxy dan objek nyata. Kode klien tidak tahu objek proxy yang sebenarnya. Kode klien berorientasi antarmuka dan hanya memegang antarmuka objek proxy.
Singkatnya, selama kode klien tidak dapat atau tidak ingin secara langsung mengakses objek yang dipanggil - ada banyak alasan untuk situasi ini, seperti membuat objek dengan overhead sistem tinggi, atau objek yang dipanggil ada pada host jarak jauh, atau fungsi objek target tidak cukup untuk memenuhi kebutuhan ... tetapi objek proxy tambahan dibuat untuk mengembalikannya ke klien untuk digunakan, jadi metode desain ini adalah mode culty.
Berikut ini menunjukkan mode proxy sederhana. Program pertama kali menyediakan antarmuka gambar, mewakili antarmuka yang diimplementasikan oleh objek gambar besar. Kode antarmuka adalah sebagai berikut:
Listing 3. Image.java
gambar antarmuka publik {void show ();}Antarmuka ini menyediakan kelas implementasi yang mensimulasikan objek gambar besar, dan konstruktor kelas implementasi menggunakan metode thread.sleep () untuk menjeda 3s. Di bawah ini adalah kode program untuk bigimage.
Listing 4. BigImage.java
// Gunakan bigimage ini untuk mensimulasikan gambar besar gambar publik BigImage Implement Image {public bigimage () {coba {// program jeda 3S Simulasi Simulasi Simulasi Overhead Thread.sleep (3000); System.out.println ("Pemuatan Gambar berhasil ...");} catch (InterruptException ex) {ex.printstacktrace ();}} // Implementasikan metode show () dalam gambar public void show () {System.out.println ("Gambar gambar besar yang sebenarnya");}}}Kode program di atas menjeda 3s, yang menunjukkan bahwa dibutuhkan overhead waktu 3S untuk membuat objek bigimage - program menggunakan penundaan ini untuk mensimulasikan overhead sistem yang disebabkan oleh memuat gambar ini. Jika mode proxy tidak digunakan, sistem akan menghasilkan penundaan 3S ketika bigimage dibuat dalam program. Untuk menghindari penundaan ini, program ini menyediakan objek proxy untuk objek bigimage, dan kelas proxy dari kelas bigimage adalah sebagai berikut.
Listing 5. ImageProxy.java
ImageProxy kelas publik mengimplementasikan gambar {// Gabungkan instance gambar sebagai gambar proxy objek gambar privat; // Gunakan entitas abstrak untuk menginisialisasi objek proxy public imageProxy (gambar gambar) {this.image = image;}/*** Tulis ulang metode show () dari antarmuka gambar* Metode ini digunakan untuk mengontrol akses ke objek proksi, dan kembali dengan objek Proxy,* show () {// Buat objek proxy saja if (image == null) {image = new bigimage ();} image.show ();}}Kelas proxy imageProxy di atas mengimplementasikan metode show () yang sama sebagai bigimage, yang memungkinkan kode klien untuk menggunakan objek proxy sebagai bigimage setelah mendapatkan objek proxy.
Logika kontrol ditambahkan ke metode show () dari kelas ImageProxy. Logika kontrol ini digunakan untuk mengontrol bahwa objek proxy bigimage akan dibuat hanya ketika sistem benar -benar memanggil show () dari gambar. Program berikut perlu menggunakan objek bigimage, tetapi program tidak secara langsung mengembalikan instance bigimage, tetapi pertama -tama mengembalikan objek proxy bigimage, seperti yang ditunjukkan dalam program berikut.
Listing 6. Bigimagetest.java
public class BigImageTest{public static void main(String[] args){long start = System.currentTimeMillis();// The program returns an Image object, which is just the proxy object of BigImage Image image = new ImageProxy(null);System.out.println("The time overhead of the system obtaining the Image object:" +(System.currentTimeMillis() - Mulai)); // Program ini akan benar -benar membuat objek proxy ketika metode show () dari proxy gambar sebenarnya disebut. image.show ();}}Program di atas menginisialisasi gambar dengan sangat cepat karena program tidak benar -benar membuat objek bigimage, tetapi hanya mendapatkan objek proxy imageproxy - sampai program memanggil metode. Jalankan program di atas dan lihat hasil yang ditunjukkan pada Gambar 6.
Gambar 6. Tingkatkan kinerja menggunakan mode proxy
Melihat hasil berjalan yang ditunjukkan pada Gambar 6, pembaca harus dapat menyetujui bahwa menggunakan mode proxy meningkatkan kinerja sistem untuk mendapatkan objek gambar. Tetapi beberapa pembaca mungkin mengajukan pertanyaan: Ketika suatu program memanggil metode show () dari objek ImageProxy, itu juga perlu membuat objek bigimage, tetapi overhead sistem belum benar -benar berkurang? Hanya saja overhead sistem ini tertunda?
Kita dapat menjawab pertanyaan ini dari dua perspektif berikut:
Menunda penciptaan bigimage sampai benar -benar dibutuhkan dapat memastikan kelancaran operasi program sebelumnya, dan mengurangi waktu kelangsungan hidup bigimage dalam memori, menyimpan overhead memori sistem dari perspektif makro.
Dalam beberapa kasus, mungkin program ini tidak akan pernah benar -benar menyebut metode show () dari objek imageProxy - yang berarti bahwa sistem tidak perlu membuat objek bigimage sama sekali. Dalam hal ini, menggunakan mode proxy dapat secara signifikan meningkatkan kinerja operasi sistem.
Benar -benar mirip, Hibernate juga menggunakan mode proxy untuk "menunda" waktu untuk memuat entitas yang terkait. Jika program tidak perlu mengakses entitas terkait, program tidak akan merangkak entitas yang terkait. Ini dapat menyimpan overhead memori sistem dan mempersingkat waktu ketika hibernasi memuat entitas.
ringkasan
Hibernate Lazy Load pada dasarnya adalah aplikasi mode proxy. Dalam beberapa tahun terakhir, kami sering menggunakan mode proxy untuk mengurangi overhead memori sistem dan meningkatkan kinerja aplikasi. Hibernate mengambil keuntungan dari keunggulan mode proxy ini dan menggabungkan javassist atau cGlib untuk secara dinamis menghasilkan objek proxy, yang menambah fleksibilitas ke mode proxy. Hibernate memberi penggunaan ini nama baru: Lazy Loading. Bagaimanapun, sepenuhnya menganalisis dan memahami implementasi kerangka kerja open source ini dapat lebih mengalami keunggulan model desain klasik.
Saya berharap deskripsi dalam artikel ini akan membantu pemrograman Java semua orang berdasarkan kerangka hibernasi.