Görünümde Hazırda Bekletme Açık Oturumu neden kötü bir uygulama olarak kabul edilir?


108

Ve LazyLoadExceptions'dan kaçınmak için ne tür alternatif stratejiler kullanıyorsunuz?

Açık oturumun şu konularla ilgili sorunları olduğunu anlıyorum:

  • Farklı jvm'lerde çalışan katmanlı uygulamalar
  • İşlemler yalnızca sonunda yapılır ve büyük olasılıkla sonuçları önceden almak istersiniz.

Ancak, uygulamanızın tek bir sanal makinede çalıştığını biliyorsanız, açık oturum stratejisi kullanarak neden ağrınızı hafifletmiyorsunuz?


12
OSIV kötü bir uygulama olarak kabul edilir mi? Kim tarafından?
Johannes Brodwall

4
Ve - iyi alternatifler nelerdir?
David Rabinowitz

7
Dikiş geliştiricilerinden gelen bu metin rahatlığı: Bu uygulamayla ilgili birkaç sorun var, en ciddi olanı, bir işlemi gerçekleştirene kadar başarılı olamayacağımızdan asla emin olamayacağımızdır, ancak "açık oturum" işlem gerçekleştirildiğinde, görünüm tamamen işlenir ve işlenen yanıt, istemciye zaten boşaltılmış olabilir. Kullanıcıya işleminin başarısız olduğunu nasıl bildirebiliriz?
darpet


2
Artıları ve eksileri ve bu konudaki
Angular University

Yanıtlar:


46

Çünkü görünüm katmanında muhtemelen başlatılmamış Proxy'leri, özellikle koleksiyonları göndermek ve buradan hazırda bekletme yüklemesini tetiklemek, hem performans hem de anlayış açısından rahatsız edici olabilir.

Anlamak :

OSIV kullanımı, veri erişim katmanıyla ilgili endişeler nedeniyle görünüm katmanını 'kirletiyor'.

Görünüm katmanı, HibernateExceptiontembel yükleme sırasında meydana gelebilecek bir durumu ele almaya hazır değildir , ancak muhtemelen veri erişim katmanıdır.

Performans :

OSIV, halının altına uygun varlık yüklemesi yapma eğilimindedir - koleksiyonlarınızın veya varlıklarınızın tembel olarak başlatıldığını (belki N + 1) fark etmeme eğilimindesiniz. Daha fazla rahatlık, daha az kontrol.


Güncelleme: Bu konuyla ilgili daha büyük bir tartışma için bkz . OpenSessionInView antipattern . Yazar üç önemli noktayı listeler:

  1. her bir tembel başlatma size bir sorgu getirecek, yani her varlık N + 1 sorguya ihtiyaç duyacaktır, burada N, tembel ilişkilendirmelerin sayısıdır. Ekranınız tablo verileri gösteriyorsa, Hazırda Bekletme günlüğünü okumak, yapmanız gerektiği gibi yapmamanız için büyük bir ipucudur.
  2. Bu, sunum katmanında tırnaklarınızı DB ile kirlettiğiniz için katmanlı mimariyi tamamen ortadan kaldırır. Bu kavramsal bir hile, bu yüzden onunla yaşayabilirim ama bir sonuç var
  3. Son olarak, en önemlisi, oturumu getirirken bir istisna meydana gelirse, sayfanın yazılması sırasında ortaya çıkacaktır: kullanıcıya temiz bir hata sayfası sunamazsınız ve yapabileceğiniz tek şey gövdeye bir hata mesajı yazmaktır.

13
Tamam, görünüm katmanını hazırda bekletme istisnasıyla 'kirletiyor'. Ancak performansla ilgili olarak, sorunun dto'nuzu döndürecek bir hizmet katmanına erişmekten oldukça benzer olduğunu düşünüyorum. Bir performans sorunuyla karşılaşırsanız, o zaman bu sorunu daha akıllı bir sorgu veya daha hafif bir dto ile optimize etmelisiniz. Görünümde ihtiyaç duyabileceğiniz olasılıkları ele almak için çok fazla hizmet yöntemi geliştirmeniz gerekiyorsa, hizmet katmanını da 'kirletiyorsunuz'. Hayır?
HeDinges

1
Bir fark, Hazırda Bekletme oturumunun kapanmasını geciktirmesidir. JSP'nin işlenmesini / yazılmasını / vb. Bekleyeceksiniz ve bu, nesneleri bellekte daha uzun süre tutacaktır. Bu, özellikle oturum tamamlama üzerine veri yazmanız gerekiyorsa bir sorun olabilir.
Robert Munteanu

8
OSIV'in Performansa zarar verdiğini söylemek mantıklı değil. DTO'lar dışında hangi alternatifler var? Bu durumda, her zaman daha düşük performansa sahip olursunuz çünkü herhangi bir görünüm tarafından kullanılan verilerin, ihtiyaç duymayan görünümler için bile yüklenmesi gerekecek.
Johannes Brodwall

11
Bence kirlilik ters yönde işliyor. Verileri yüklemem gerekirse, mantık katmanının (veya daha kötüsü veri erişim katmanının) bir nesnenin hangi şekilde görüntüleneceğini bilmesi gerekir. Görünümü değiştirirseniz ihtiyacınız olmayan veya ihtiyacınız olan eksik nesneleri yüklersiniz. Hazırda Bekletme İstisnası bir hatadır ve diğer herhangi bir beklenmedik istisna kadar zehirleyicidir. Ancak performans bir sorundur. Performans ve ölçeklenebilirlik sorunları sizi veri erişim katmanınızda daha fazla düşünmeye ve çalışmaya zorlayacak ve muhtemelen oturumu daha erken kapatmaya zorlayacaktır
Jens Schauder

1
@JensSchauder "Görünümü değiştirirseniz ihtiyacınız olmayan şeyler yükler veya ihtiyacınız olan nesneleri kaçırırsınız". Bu aynen öyle. Görünümü değiştirirseniz, görünümün yüklenmesine izin vermektense, ihtiyaç duymadığınız şeyleri yüklemek (onları almak için daha istekli olacağınızdan) veya eksik nesneleri bulmak için Lazy yükleme istisnasını almak çok daha iyidir. tembel bir şekilde bu N + 1 sorununa yol açacaktır ve bunun olduğunu bile bilmeyeceksiniz. Bu yüzden IMO, hizmet katmanı (ve siz) ne gönderildiğini, görünümün tembel bir şekilde yüklenmesinden daha iyidir ve siz onun hakkında hiçbir şey bilmiyorsunuz.
Jeshurun

40

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.

görüntü açıklamasını buraya girin

  • OpenSessionInViewFilterAramaları openSessiontemel yöntemi SessionFactoryve yeni elde Session.
  • SessionBağlıdır TransactionSynchronizationManager.
  • OpenSessionInViewFilterAramaları doFilterbir javax.servlet.FilterChainamacı, referans ve daha ayrıntılı işlenir
  • DispatcherServletDenir ve altta yatan için bu yolları HTTP isteği olduğunu PostController.
  • PostControllerÇağrılar PostServicelistesini almak için Postkişiler.
  • PostServiceYeni bir işlem açar ve HibernateTransactionManageraynı yeniden kullanır Sessiontarafından açıldığını OpenSessionInViewFilter.
  • PostDAOListesini getirir Postherhangi tembel ilişki başlatılıyor dışındaki varlıklar.
  • PostServiceAltında yatan işlem taahhüt, ama Sessiono dışarıdan açıldı çünkü kapalı değil.
  • Başlangıçlar DispatcherServletkullanıcı arayüzünü oluşturmaya başlar ve bu da tembel ilişkilendirmelerde gezinir ve bunların başlatılmasını tetikler.
  • OpenSessionInViewFilterKapatabilir Sessionve 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, @BatchSizeilişkilendirmeleri toplu olarak FetchMode.SUBSELECTgetirmeyi 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.propertiesyapı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 .


3
Görünümde Açık Oturumu otomatik tamamlama ile kullanmak mümkündür, ancak Hazırda Bekletme geliştiricilerinin amaçladığı şekilde değildir. Dolayısıyla, Görünümde Açık Oturum'un dezavantajları olsa da, otomatik kesinleştirme bir değildir çünkü onu kapatabilir ve yine de kullanabilirsiniz.
stefan.m

Bir işlemin içinde olanlardan bahsediyorsunuz ve bu doğru. Ancak Web Katmanı oluşturma aşaması Hazırda Bekletme dışında gerçekleşir, bu nedenle otomatik taahhüt moduna geçersiniz. Mantıklı?
Vlad Mihalcea

Bence bu, Görünümde Açık Oturum için ideal olmayan bir değişken. Görünüm işlenene kadar oturum ve işlem açık kalmalıdır, bu durumda otomatik tamamlama moduna gerek yoktur.
stefan.m

2
Oturum açık kalır. Ancak işlem gerçekleşmez. İşlemin tüm süreç boyunca yayılması, uzunluğunu artırdığı ve kilitler gerekenden daha uzun süre tutulduğu için optimal değildir. Görünüm bir RuntimeException atarsa ​​ne olacağını hayal edin. UI oluşturma başarısız olduğu için işlem geri alınacak mı?
Vlad Mihalcea

Çok detaylı cevap için çok teşekkür ederim! İlkbahar önyükleme kullanıcıları muhtemelen bu şekilde jpa kullanmayacağından kılavuzu sonunda değiştirirdim.
Skeeve

24
  • işlemler hizmet katmanında gerçekleştirilebilir - işlemler OSIV ile ilgili değildir. Devam Sessioneden bir işlem değil, açık kalan şeydir.

  • Başvurunuz katmanları birden fazla bilgisayarda yayılmış ise, o zaman hemen hemen edemez OSIV kullanmak - Eğer tel üzerinden nesneyi göndermeden önce gereken herşeye başlatmak zorundayız.

  • OSIV, tembel yüklemenin performans avantajlarından yararlanmanın güzel ve şeffaf bir yoludur (yani kodunuzdan hiçbiri bunun olduğunun farkında değildir)


2
İlk madde işareti ile ilgili olarak, bu en azından JBoss wiki'deki orijinal OSIV için doğru değildir , aynı zamanda istek etrafındaki işlem sınırlarını da ele alır.
Pascal Thivent

@PascalThivent Hangi kısmı seni böyle düşündürdü?
Sanghyun Lee

13

Açık Oturum Görüşünün kötü bir uygulama olarak kabul edildiğini söyleyemem; sana bu izlenimi ne veriyor?

Açık Oturum Görünümde, Hazırda Bekletme ile oturumları yönetmeye yönelik basit bir yaklaşımdır. Basit olduğu için bazen basittir. Bir istekte birden fazla işlem olması gibi işlemleriniz üzerinde ayrıntılı kontrole ihtiyacınız varsa, Açık Oturum Görünümde her zaman iyi bir yaklaşım değildir.

Diğerlerinin de belirttiği gibi, OSIV için bazı ödünleşimler var - N + 1 sorununa çok daha yatkınsınız çünkü hangi işlemleri başlattığınızı fark etme olasılığınız daha düşük. Aynı zamanda, görünümünüzdeki küçük değişikliklere uyum sağlamak için hizmet katmanınızı değiştirmenize gerek olmadığı anlamına gelir.


5

Spring gibi bir Kontrolü Ters Çevirme (IoC) konteyneri kullanıyorsanız, fasulye kapsamı hakkında bilgi almak isteyebilirsiniz . Esasen, Spring'e bana Sessionyaşam döngüsü tüm isteği kapsayan bir Hazırda Bekletme nesnesi vermesini söylüyorum (yani, HTTP isteğinin başında ve sonunda oluşturulur ve yok edilir). LazyLoadExceptionIoC konteyneri bunu benim için yönettiği için seansları veya seansı kapatmak için endişelenmeme gerek yok .

Belirtildiği gibi, N + 1 SELECT performans sorunlarını düşünmeniz gerekecek. Daha sonra, performansın sorun olduğu yerlerde istekli katılma yüklemesi yapmak için Hazırda Beklet varlığınızı her zaman yapılandırabilirsiniz.

Fasulye kapsam belirleme çözümü, Bahara özgü değildir. PicoContainer'ın da aynı özelliği sunduğunu biliyorum ve diğer olgun IoC konteynerlerinin de benzer bir şey sunduğundan eminim.


1
Kapsamlı fasulye talebi aracılığıyla görünümde kullanıma sunulan Hazırda Bekletme oturumlarının gerçek bir uygulamasına ilişkin bir işaretçiniz var mı?
Marvo

4

Kendi tecrübelerime göre OSIV o kadar da kötü değil. Yaptığım tek düzenleme iki farklı işlem kullanmaktı: - birincisi, "iş mantığına" sahip olduğum "hizmet katmanında" açıldı - ikincisi, görünüm oluşturmadan hemen önce açıldı


3

Blogumda açık oturumun ne zaman kullanılacağına dair bazı yönergeler üzerine bir yazı yazdım. İlgileniyorsanız kontrol edin.

http://heapdump.wordpress.com/2010/04/04/should-i-use-open-session-in-view/


1
Genel bir genel SO kuralı olarak, eğer bir cevap veriyorsanız, başka bir yere bağlantı kurmaktan daha fazlasını yapmak en iyisidir. Belki bir veya iki cümle ya da ana fikri veren listelenmiş maddeler sağlayın. Bağlamak sorun değil, ancak biraz daha fazla değer sağlamak istiyorsunuz. Aksi takdirde, yalnızca yorum yapmak ve bağlantıyı oraya koymak isteyebilirsiniz.
DWright

bu yanıttaki bağlantı okumaya değer, OSIV'in ne zaman kullanılacağı konusunda iyi bir rehberlik sağlıyor
ams

1

Hazırda Bekletme'de v. Paslandım .. ancak bir Hazırda Bekletme oturumunda birden fazla işlem yapmanın mümkün olduğunu düşünüyorum. Dolayısıyla işlem sınırlarınızın oturum başlatma / durdurma olaylarıyla aynı olması gerekmez.

OSIV, imo, öncelikle yararlıdır çünkü isteğin bir DB erişimi yapması gerektiğinde bir 'kalıcılık bağlamı' (diğer adıyla oturum) başlatmak için kod yazmaktan kaçınabiliriz.

Hizmet katmanınızda, muhtemelen 'Gerekli, Yeni Gerekli, vb.' Gibi farklı işlem ihtiyaçları olan yöntemlere çağrı yapmanız gerekecektir. Bu yöntemlerin ihtiyaç duyduğu tek şey, birinin (yani OSIV filtresinin) kalıcılık bağlamını başlatmasıdır, bu yüzden endişelenmeleri gereken tek şey - "bu iş parçacığı için bana hazırda bekletme oturumunu verin .. Biraz yapmam gerekiyor DB şeyler ".


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.