Dan jenis strategi alternatif apa yang Anda gunakan untuk menghindari LazyLoadExceptions?
Saya mengerti bahwa sesi terbuka yang dilihat memiliki masalah dengan:
- Aplikasi berlapis yang berjalan di jvm berbeda
- Transaksi dilakukan hanya di akhir, dan kemungkinan besar Anda akan menyukai hasilnya sebelumnya.
Tetapi, jika Anda tahu bahwa aplikasi Anda berjalan pada satu vm, mengapa tidak meringankan rasa sakit Anda dengan menggunakan sesi terbuka dalam strategi tampilan?
java
hibernate
jpa
lazy-loading
open-session-in-view
HeDinges
sumber
sumber
Jawaban:
Karena mengirim Proxies yang mungkin tidak diinisialisasi, terutama koleksi, di lapisan tampilan dan memicu pemuatan hibernasi dari sana dapat mengganggu baik dari sudut pandang kinerja maupun pemahaman.
Pengertian :
Menggunakan OSIV 'mengotori' lapisan tampilan dengan masalah yang terkait dengan lapisan akses data.
Lapisan tampilan tidak bersiap untuk menangani
HibernateException
yang mungkin terjadi saat pemuatan lambat, tetapi mungkin lapisan akses datanya.Performa :
OSIV cenderung menarik pemuatan entitas yang tepat di bawah karpet - Anda cenderung tidak memperhatikan bahwa koleksi atau entitas Anda dimulai dengan malas (mungkin N + 1). Lebih nyaman, lebih sedikit kontrol.
Pembaruan: lihat Antipattern OpenSessionInView untuk diskusi yang lebih besar mengenai subjek ini. Penulis membuat daftar tiga poin penting:
sumber
Untuk penjelasan yang lebih panjang, Anda dapat membaca artikel Open Session In View Anti-Pattern saya . Jika tidak, berikut adalah ringkasan mengapa Anda tidak boleh menggunakan Sesi Terbuka Dalam Tampilan.
Sesi Terbuka Dalam Tampilan mengambil pendekatan yang buruk untuk mengambil data. Alih-alih membiarkan lapisan bisnis memutuskan cara terbaik untuk mengambil semua pengaitan yang dibutuhkan oleh lapisan Tampilan, ini memaksa Konteks Persistensi untuk tetap terbuka sehingga lapisan Tampilan dapat memicu inisialisasi Proxy.
OpenSessionInViewFilter
menyebutopenSession
metode yang mendasariSessionFactory
dan memperoleh baruSession
.Session
terikat keTransactionSynchronizationManager
.OpenSessionInViewFilter
menyebutdoFilter
darijavax.servlet.FilterChain
referensi objek dan permintaan itu diproses lebih lanjutDispatcherServlet
disebut, dan rute permintaan HTTP ke mendasariPostController
.PostController
panggilanPostService
untuk mendapatkan daftarPost
entitas.PostService
membuka transaksi baru, danHibernateTransactionManager
menggunakan kembali samaSession
yang dibuka olehOpenSessionInViewFilter
.PostDAO
menjemput daftarPost
entitas tanpa menginisialisasi setiap asosiasi malas.PostService
melakukan transaksi yang mendasarinya, tetapiSession
tidak tertutup karena dibuka secara eksternal.DispatcherServlet
dimulai rendering UI, yang, pada gilirannya, menavigasi asosiasi malas dan memicu inisialisasi mereka.OpenSessionInViewFilter
dapat menutupSession
, dan koneksi database yang mendasari dilepaskan juga.Pada pandangan pertama, ini mungkin tidak terlihat seperti hal yang buruk untuk dilakukan, tetapi, setelah Anda melihatnya dari perspektif database, serangkaian kekurangan mulai menjadi lebih jelas.
Lapisan layanan membuka dan menutup transaksi database, tetapi setelah itu, tidak ada transaksi eksplisit yang terjadi. Karena alasan ini, setiap pernyataan tambahan yang dikeluarkan dari fase rendering UI dijalankan dalam mode komit otomatis. Komitmen otomatis memberi tekanan pada server database karena setiap pernyataan harus membuang log transaksi ke disk, sehingga menyebabkan banyak lalu lintas I / O di sisi database. Satu optimasi akan menandai
Connection
sebagai read-only yang akan memungkinkan server database untuk menghindari penulisan ke log transaksi.Tidak ada lagi pemisahan masalah karena pernyataan dibuat oleh lapisan layanan dan proses rendering UI. Menulis pengujian integrasi yang menegaskan jumlah pernyataan yang dihasilkan harus melalui semua lapisan (web, layanan, DAO), sementara aplikasi diterapkan di wadah web. Bahkan ketika menggunakan database dalam memori (misalnya HSQLDB) dan web server yang ringan (misalnya Jetty), pengujian integrasi ini akan lebih lambat untuk dieksekusi daripada jika lapisan dipisahkan dan pengujian integrasi back-end menggunakan database, sedangkan pengujian integrasi front-end mengejek lapisan layanan sama sekali.
Lapisan UI terbatas untuk menavigasi asosiasi yang pada gilirannya dapat memicu masalah kueri N + 1. Meskipun Hibernate menawarkan
@BatchSize
untuk mengambil pengaitan dalam kelompok, danFetchMode.SUBSELECT
untuk mengatasi skenario ini, anotasi memengaruhi rencana pengambilan default, sehingga anotasi tersebut diterapkan ke setiap kasus penggunaan bisnis. Untuk alasan ini, kueri lapisan akses data jauh lebih cocok karena dapat disesuaikan untuk kebutuhan pengambilan data kasus penggunaan saat ini.Last but not least, koneksi database dapat diadakan selama fase rendering UI (tergantung pada mode rilis koneksi Anda) yang meningkatkan waktu sewa koneksi dan membatasi throughput transaksi secara keseluruhan karena kemacetan pada kumpulan koneksi database. Semakin banyak koneksi ditahan, semakin banyak permintaan bersamaan lainnya yang akan menunggu untuk mendapatkan koneksi dari pool.
Jadi, jika koneksi Anda ditahan terlalu lama, Anda bisa memperoleh / melepaskan beberapa koneksi untuk satu permintaan HTTP, oleh karena itu memberi tekanan pada kumpulan koneksi yang mendasarinya dan membatasi skalabilitas.
Sepatu Musim Semi
Sayangnya, Sesi Terbuka dalam Tampilan diaktifkan secara default di Spring Boot .
Jadi, pastikan bahwa di
application.properties
file konfigurasi, Anda memiliki entri berikut:Ini akan menonaktifkan OSIV, sehingga Anda dapat menangani dengan
LazyInitializationException
cara yang benar .sumber
transaksi dapat dilakukan di lapisan layanan - transaksi tidak terkait dengan OSIV. Itu
Session
yang tetap terbuka, bukan transaksi - berjalan.jika lapisan aplikasi Anda tersebar di beberapa mesin, maka Anda tidak dapat menggunakan OSIV - Anda harus menginisialisasi semua yang Anda butuhkan sebelum mengirim objek melalui kabel.
OSIV adalah cara yang bagus dan transparan (yaitu - tidak ada kode Anda yang menyadari bahwa hal itu terjadi) untuk memanfaatkan manfaat kinerja dari pemuatan lambat
sumber
Saya tidak akan mengatakan bahwa Open Session In View dianggap sebagai praktik yang buruk; apa yang memberimu kesan itu?
Open-Session-In-View adalah pendekatan sederhana untuk menangani sesi dengan Hibernate. Karena sederhana, terkadang juga sederhana. Jika Anda memerlukan kontrol yang sangat cermat atas transaksi Anda, seperti memiliki beberapa transaksi dalam satu permintaan, Open-Session-In-View tidak selalu merupakan pendekatan yang baik.
Seperti yang ditunjukkan orang lain, ada beberapa trade-off untuk OSIV - Anda jauh lebih rentan terhadap masalah N + 1 karena Anda cenderung tidak menyadari transaksi apa yang Anda mulai. Pada saat yang sama, ini berarti Anda tidak perlu mengubah lapisan layanan Anda untuk beradaptasi dengan perubahan kecil pada tampilan Anda.
sumber
Jika Anda menggunakan wadah Inversion of Control (IoC) seperti Spring, Anda mungkin ingin membaca tentang pelingkupan kacang . Pada dasarnya, saya memberi tahu Spring untuk memberi saya
Session
objek Hibernate yang siklus hidupnya mencakup seluruh permintaan (yaitu, dibuat dan dihancurkan pada awal dan akhir permintaan HTTP). Saya tidak perlu khawatir tentangLazyLoadException
atau menutup sesi karena wadah IoC mengaturnya untuk saya.Seperti disebutkan, Anda harus memikirkan masalah kinerja N + 1 SELECT. Anda selalu dapat mengkonfigurasi entitas Hibernate Anda setelah itu untuk melakukan pemuatan gabungan yang bersemangat di tempat-tempat di mana kinerja menjadi masalah.
Solusi pelingkupan kacang bukan khusus Musim Semi. Saya tahu PicoContainer menawarkan kemampuan yang sama dan saya yakin wadah IoC dewasa lainnya menawarkan sesuatu yang serupa.
sumber
Menurut pengalaman saya sendiri, OSIV tidak terlalu buruk. Satu-satunya pengaturan yang saya buat adalah menggunakan dua transaksi berbeda: - yang pertama, dibuka di "lapisan layanan", di mana saya memiliki "logika bisnis" - yang kedua dibuka tepat sebelum rendering tampilan
sumber
Saya baru saja membuat posting tentang beberapa pedoman tentang kapan menggunakan sesi terbuka dalam tampilan di blog saya. Lihat jika Anda tertarik.
http://heapdump.wordpress.com/2010/04/04/should-i-use-open-session-in-view/
sumber
Saya sangat berkarat pada Hibernate .. tapi saya pikir mungkin untuk memiliki banyak transaksi dalam satu sesi Hibernate. Jadi, batasan transaksi Anda tidak harus sama dengan peristiwa awal / penghentian sesi.
OSIV, imo, terutama berguna karena kita dapat menghindari penulisan kode untuk memulai 'konteks persistensi' (alias sesi) setiap kali permintaan perlu membuat akses DB.
Di lapisan layanan Anda, Anda mungkin perlu melakukan panggilan ke metode yang memiliki kebutuhan transaksi berbeda, seperti 'Wajib, Wajib Baru, dll.' Satu-satunya hal yang diperlukan metode ini adalah bahwa seseorang (yaitu filter OSIV) telah memulai konteks ketekunan, sehingga satu-satunya hal yang perlu mereka khawatirkan adalah - "hei, beri saya sesi hibernasi untuk utas ini .. Saya perlu melakukan beberapa Barang DB ".
sumber
Ini tidak akan banyak membantu tetapi Anda dapat memeriksa topik saya di sini: * Hibernate Cache1 OutOfMemory dengan OpenSessionInView
Saya memiliki beberapa masalah OutOfMemory karena OpenSessionInView dan banyak entitas dimuat, karena mereka tetap berada di cache Hibernate level1 dan tidak dikumpulkan sampah (saya memuat banyak entitas dengan 500 item per halaman, tetapi semua entitas tetap dalam cache)
sumber