Daha uzun bir açıklama için, Desen Karşıtı Görünümde Açık Oturum makalemi okuyabilirsiniz. Aksi takdirde, Açık Oturumu Görünümde neden kullanmamanız gerektiğine dair bir özet burada.
Görünümde Açık Oturum, verileri almak için kötü bir yaklaşım sergiliyor. Görünüm katmanının ihtiyaç duyduğu tüm ilişkilendirmeleri en iyi nasıl getireceğine iş katmanının karar vermesine izin vermek yerine, Görünüm katmanının Proxy başlatmayı tetikleyebilmesi için Kalıcı Bağlamı açık kalmaya zorlar.
OpenSessionInViewFilter
Aramaları openSession
temel yöntemi SessionFactory
ve yeni elde Session
.
Session
Bağlıdır TransactionSynchronizationManager
.
OpenSessionInViewFilter
Aramaları doFilter
bir javax.servlet.FilterChain
amacı, referans ve daha ayrıntılı işlenir
DispatcherServlet
Denir ve altta yatan için bu yolları HTTP isteği olduğunu PostController
.
PostController
Çağrılar PostService
listesini almak için Post
kişiler.
PostService
Yeni bir işlem açar ve HibernateTransactionManager
aynı yeniden kullanır Session
tarafından açıldığını OpenSessionInViewFilter
.
PostDAO
Listesini getirir Post
herhangi tembel ilişki başlatılıyor dışındaki varlıklar.
PostService
Altında yatan işlem taahhüt, ama Session
o dışarıdan açıldı çünkü kapalı değil.
- Başlangıçlar
DispatcherServlet
kullanıcı arayüzünü oluşturmaya başlar ve bu da tembel ilişkilendirmelerde gezinir ve bunların başlatılmasını tetikler.
OpenSessionInViewFilter
Kapatabilir Session
ve altta yatan veritabanı bağlantısı sıra serbest bırakılır.
İlk bakışta, bu yapılacak çok kötü bir şey gibi görünmeyebilir, ancak bir veritabanı perspektifinden baktığınızda, bir dizi kusur daha belirgin hale gelmeye başlar.
Hizmet katmanı bir veritabanı işlemini açar ve kapatır, ancak daha sonra devam eden açık bir işlem yoktur. Bu nedenle, kullanıcı arabirimi oluşturma aşamasından yayınlanan her ek ifade, otomatik kesinleştirme modunda yürütülür. Otomatik kesinleştirme, veritabanı sunucusuna baskı uygular, çünkü her bir ifade işlem günlüğünü diske aktarmalıdır, bu nedenle veritabanı tarafında çok fazla G / Ç trafiğine neden olur. Optimizasyonlardan biri Connection
, veritabanı sunucusunun işlem günlüğüne yazmaktan kaçınmasına izin verecek şekilde salt okunur olarak işaretlemek olacaktır.
Artık endişelerin ayrılması yok çünkü ifadeler hem hizmet katmanı hem de UI oluşturma işlemi tarafından üretiliyor. Oluşturulan ifadelerin sayısını belirten entegrasyon testleri yazmak , uygulamayı bir web kapsayıcısına yerleştirirken tüm katmanlardan (web, hizmet, DAO) geçmeyi gerektirir. Bir bellek içi veritabanı (ör. HSQLDB) ve hafif bir web sunucusu (ör. Jetty) kullanıldığında bile, bu entegrasyon testlerinin yürütülmesi, katmanların ayrılmasına ve arka uç entegrasyon testlerinin veritabanını kullanmasına göre daha yavaş olacaktır. ön uç entegrasyon testleri, hizmet katmanını tamamen alay ediyordu.
UI katmanı, sırayla N + 1 sorgu problemlerini tetikleyebilecek gezinme ilişkileri ile sınırlıdır. Hibernate, @BatchSize
ilişkilendirmeleri toplu olarak FetchMode.SUBSELECT
getirmeyi ve bu senaryoyla başa çıkmayı teklif etse de , ek açıklamalar varsayılan getirme planını etkilediğinden, her iş kullanım durumuna uygulanır. Bu nedenle, bir veri erişim katmanı sorgusu çok daha uygundur çünkü mevcut kullanım durumu veri getirme gereksinimleri için uyarlanabilir.
Son olarak, veritabanı bağlantısı, kullanıcı arabirimi oluşturma aşaması boyunca (bağlantı bırakma modunuza bağlı olarak) tutulabilir, bu da bağlantı kiralama süresini artırır ve veritabanı bağlantı havuzundaki tıkanıklık nedeniyle genel işlem hacmini sınırlar. Bağlantı ne kadar tutulursa, havuzdan bağlantı almak için eşzamanlı talepler o kadar fazla bekleyecektir.
Yani, ya bağlantıyı çok uzun süre tutarsınız, ya tek bir HTTP isteği için birden çok bağlantı alırsınız / bırakırsınız, bu nedenle temel bağlantı havuzuna baskı uygular ve ölçeklenebilirliği sınırlar.
Spring Boot
Maalesef Görünümde Açık Oturum, Spring Boot'da varsayılan olarak etkindir .
Bu nedenle, application.properties
yapılandırma dosyasında aşağıdaki girişe sahip olduğunuzdan emin olun :
spring.jpa.open-in-view=false
Bu, OSIV'i devre dışı bırakacak, böylece doğru şekilde idareLazyInitializationException
edebileceksiniz .