Saya cenderung menggunakan Hibernate dalam kombinasi dengan kerangka kerja Spring dan kemampuan demarkasi transaksi deklaratifnya (misalnya, @Transactional ).
Seperti yang kita semua ketahui, hibernasi berusaha menjadi non-invasif dan setransparan mungkin, namun ini terbukti sedikit lebih menantang saat menggunakan lazy-loaded
hubungan.
Saya melihat sejumlah alternatif desain dengan tingkat transparansi berbeda.
- Jadikan hubungan tidak lambat (mis.,
fetchType=FetchType.EAGER)
- Ini membatalkan keseluruhan gagasan pemuatan lambat ..
- Inisialisasi koleksi menggunakan
Hibernate.initialize(proxyObj);
- Ini menyiratkan kopling yang relatif tinggi ke DAO
- Meskipun kita bisa mendefinisikan antarmuka dengan
initialize
, implementasi lain tidak dijamin akan memberikan yang setara.
- Tambahkan perilaku transaksi ke
Model
objek persisten itu sendiri (menggunakan proxy dinamis atau@Transactional
)- Saya belum mencoba pendekatan proxy dinamis, meskipun saya sepertinya tidak pernah mendapatkan @Transactional mengerjakan objek persisten itu sendiri. Mungkin karena hibernasi itu adalah operasi pada proxy yang akan digunakan.
- Kehilangan kendali saat transaksi benar-benar terjadi
- Sediakan API lazy / non-lazy, misalnya,
loadData()
danloadDataWithDeps()
- Memaksa aplikasi untuk mengetahui kapan harus menggunakan rutin yang mana, lagi kopling yang ketat
- Metode overflow
loadDataWithA()
, ....,loadDataWithX()
- Paksa pencarian dependensi, misalnya dengan hanya menyediakan
byId()
operasi- Membutuhkan banyak rutinitas yang berorientasi non-objek, misalnya,
findZzzById(zid)
dan kemudiangetYyyIds(zid)
bukannyaz.getY()
- Akan berguna untuk mengambil setiap objek dalam koleksi satu per satu jika ada overhead pemrosesan yang besar di antara transaksi.
- Membutuhkan banyak rutinitas yang berorientasi non-objek, misalnya,
- Jadikan bagian dari aplikasi @Transactional, bukan hanya DAO
- Pertimbangan yang mungkin untuk transaksi bersarang
- Membutuhkan rutinitas yang disesuaikan untuk manajemen transaksi (misalnya, cukup kecil)
- Dampak programatik kecil, meskipun dapat mengakibatkan transaksi besar
- Berikan DAO dengan profil pengambilan dinamis , misalnya,
loadData(id, fetchProfile);
- Aplikasi harus mengetahui profil mana yang akan digunakan kapan
- Jenis transaksi AoP, misalnya, operasi intersepsi dan melakukan transaksi bila diperlukan
- Memerlukan manipulasi kode byte atau penggunaan proxy
- Kehilangan kendali saat transaksi dilakukan
- Ilmu hitam, seperti biasa :)
Apakah saya melewatkan opsi apa pun?
Manakah pendekatan pilihan Anda saat mencoba meminimalkan dampak lazy-loaded
hubungan dalam desain aplikasi Anda?
(Oh, dan maaf untuk WoT )
java
hibernate
spring
lazy-loading
application-design
Johan Sjöberg
sumber
sumber
Jawaban:
Saya akan mengatakan asumsi awal salah. Persistensi transaparent adalah mitos, karena aplikasi harus selalu menjaga siklus hidup entitas dan ukuran grafik objek yang dimuat.
Perhatikan bahwa Hibernate tidak dapat membaca pikiran, oleh karena itu jika Anda mengetahui bahwa Anda memerlukan sekumpulan dependensi tertentu untuk operasi tertentu, Anda perlu mengungkapkan niat Anda untuk Hibernate.
Dari sudut pandang ini, solusi yang mengungkapkan maksud ini secara eksplisit (yaitu, 2, 4 dan 7) terlihat masuk akal dan tidak menderita karena kurangnya transparansi.
sumber
Saya tidak yakin masalah mana (yang disebabkan oleh kemalasan) yang Anda maksud, tetapi bagi saya rasa sakit terbesar adalah menghindari kehilangan konteks sesi dalam cache aplikasi saya sendiri. Kasus tipikal:
foo
dimuat dan dimasukkan ke dalam peta;foo.getBar()
(sesuatu yang tidak pernah dipanggil sebelumnya dan dievaluasi secara malas);Jadi, untuk mengatasi ini kami memiliki sejumlah aturan:
OpenSessionInViewFilter
untuk webapps);try/finally
) sehingga subclass tidak perlu memikirkannya;Ini, seperti yang Anda lihat, memang tidak mendekati non-invasif dan transparan . Tapi biayanya masih lumayan, dibandingkan dengan harga yang harus saya bayar untuk eager loading. Masalah dengan yang terakhir adalah terkadang hal itu mengarah pada efek kupu-kupu saat memuat objek referensi tunggal, apalagi kumpulan entitas. Konsumsi memori, penggunaan CPU, dan latensi juga jauh lebih buruk, jadi saya rasa saya bisa menerimanya.
sumber
transparency
adalah dari memaksa aplikasi untuk memperhatikan pemuatan objek yang lambat. Jika semuanya diambil dengan penuh semangat, aplikasi dapat sepenuhnya tidak menyadari apakah objek disimpan ke dalam database atau tidak, karenaFoo.getBar()
akan selalu berhasil. >when passing objects between threads, pass IDs
, ya, ini akan sesuai dengan # 5.Pola yang sangat umum adalah menggunakan OpenEntityManagerInViewFilter jika Anda sedang membuat aplikasi web.
Jika Anda membangun layanan, saya akan membuka TX pada metode publik layanan, bukan pada DAO, karena metode yang sangat sering diperlukan untuk mendapatkan atau memperbarui beberapa entitas.
Ini akan menyelesaikan semua "pengecualian Beban Malas". Jika Anda membutuhkan sesuatu yang lebih canggih untuk penyetelan kinerja, menurut saya profil pengambilan adalah cara yang tepat.
sumber
OSIV
ini masih antipattern dan menyebabkan masalah yang sangat serius seperti ketidakmampuan untuk menangani pengecualian atau penurunan kinerja dengan baik. Singkatnya: IMHO OSIV adalah solusi yang santai, tetapi hanya bagus untuk proyek mainan.