दृश्य में हाइबरनेट ओपन सत्र को एक बुरा अभ्यास क्यों माना जाता है?


108

और LazyLoadException से बचने के लिए आप किस प्रकार की वैकल्पिक रणनीतियों का उपयोग करते हैं?

मुझे यह समझ में आता है कि खुले सत्र के साथ मुद्दे हैं:

  • विभिन्न jvm में चल रहे स्तरित अनुप्रयोग
  • लेन-देन केवल अंत में किए जाते हैं, और सबसे अधिक शायद आप परिणाम पहले चाहते हैं।

लेकिन, यदि आप जानते हैं कि आपका आवेदन एक एकल vm पर चल रहा है, तो दृश्य रणनीति में एक खुले सत्र का उपयोग करके अपने दर्द को कम क्यों न करें?


12
क्या OSIV को एक बुरा अभ्यास माना जाता है? किसके द्वारा?
जोहान्स ब्रोडवॉल

4
और - अच्छे विकल्प क्या हैं?
डेविड राबिनोविट

7
सीम डेवलपर्स से अगर पाठ की यह शांति: इस कार्यान्वयन के साथ कई समस्याएं हैं, तो सबसे गंभीर यह है कि हम कभी भी यह सुनिश्चित नहीं कर सकते हैं कि जब तक हम "खुला सत्र" लेनदेन के लिए प्रतिबद्ध नहीं है, तब तक एक लेनदेन सफल होता है। दृश्य पूरी तरह से प्रदान किया गया है, और प्रदान की गई प्रतिक्रिया पहले से ही क्लाइंट को फ्लश हो सकती है। हम उपयोगकर्ता को कैसे सूचित कर सकते हैं कि उनका लेनदेन असफल था?
डेरापेट

और यहाँ लिंक है: redhat.com/docs/manuals/jboss/jboss-eap-4.2/doc/seam/…
darpet

2
पेशेवरों और विपक्ष के लिए इस ब्लॉग पोस्ट को देखें और इसके बारे में मेरा अपना अनुभव - blog.jhades.org/open-session-in-view-pattern-pros-and-cons
Angular University

जवाबों:


46

क्योंकि संभावित रूप से असंगठित प्रॉक्सी भेजना, विशेष रूप से संग्रह, दृश्य परत में और वहाँ से हाइबरनेट लोडिंग को ट्रिगर करना, दोनों प्रदर्शन और समझने के दृष्टिकोण से परेशान हो सकते हैं।

समझ :

OSIV 'प्रदूषकों' का उपयोग डेटा एक्सेस लेयर से संबंधित चिंताओं के साथ दृश्य परत को करता है।

दृश्य परत को संभालने के लिए तैयार नहीं है HibernateExceptionजो आलसी लोड होने पर हो सकता है, लेकिन संभवतः डेटा एक्सेस परत है।

प्रदर्शन :

OSIV कालीन के नीचे उचित इकाई लोड करने की कोशिश करता है - आप इस बात पर ध्यान नहीं देते हैं कि आपके संग्रह या इकाइयां lazily initialized हैं (शायद N + 1)। अधिक सुविधा, कम नियंत्रण।


अद्यतन: इस विषय के बारे में एक बड़ी चर्चा के लिए OpenSessionInView एंटीपैटर्न देखें । लेखक तीन महत्वपूर्ण बिंदुओं को सूचीबद्ध करता है:

  1. प्रत्येक आलसी आरंभीकरण से आपको एक क्वेरी मिलेगी जिसका अर्थ है कि प्रत्येक इकाई को N + 1 प्रश्नों की आवश्यकता होगी, जहां N आलसी संघों की संख्या है। यदि आपकी स्क्रीन सारणीबद्ध डेटा प्रस्तुत करती है, तो हाइबरनेट का लॉग पढ़ना एक बड़ा संकेत है जो आपको वैसा नहीं करना चाहिए जैसा आपको करना चाहिए
  2. यह पूरी तरह से स्तरित वास्तुकला को हरा देता है, क्योंकि आप प्रस्तुति परत में डीबी के साथ अपने नाखूनों को सलीके से रखते हैं। यह एक वैचारिक सम्मेलन है, इसलिए मैं इसके साथ रह सकता था लेकिन एक कोरोलरी है
  3. अंतिम लेकिन कम से कम, यदि सत्र लेते समय कोई अपवाद होता है, तो यह पृष्ठ के लेखन के दौरान होगा: आप उपयोगकर्ता को एक स्वच्छ त्रुटि पृष्ठ प्रस्तुत नहीं कर सकते हैं और केवल एक चीज जो आप कर सकते हैं वह है शरीर में त्रुटि संदेश लिखना।

13
ठीक है, यह हाइबरनेट अपवाद के साथ दृश्य परत को प्रदूषित करता है। लेकिन, प्रदर्शन के संबंध में, मुझे लगता है कि समस्या उस सेवा परत तक पहुँचने की तुलना में काफी समान है जो आपके dto को लौटा देगी। यदि आपको एक प्रदर्शन समस्या का सामना करना पड़ता है, तो आपको उस विशिष्ट मुद्दे को एक चालाक क्वेरी या अधिक हल्के डोटो के साथ अनुकूलित करना चाहिए। यदि आपको संभावनाओं को संभालने के लिए बहुत अधिक सेवा विधियाँ विकसित करनी हैं, तो आपको सेवा परत को 'प्रदूषित' भी करना होगा। नहीं?
HeDinges

1
एक अंतर यह है कि यह हाइबरनेट सत्र के समापन में देरी करता है। आप JSP के रेंडर / लिखित / आदि होने का इंतजार करेंगे, और इससे ऑब्जेक्ट्स लंबे समय तक याद रहेंगे। यदि आपको सत्र कमिट पर डेटा लिखने की आवश्यकता होती है तो यह एक समस्या हो सकती है।
रॉबर्ट मुंटेनू

8
यह कहने का कोई मतलब नहीं है कि OSIV प्रदर्शन को नुकसान पहुंचाता है। डीटीओ का उपयोग करने के अलावा क्या विकल्प हैं? उस स्थिति में, आपके पास हमेशा कम प्रदर्शन होगा क्योंकि किसी भी दृश्य द्वारा उपयोग किए जाने वाले डेटा को उन विचारों के लिए भी लोड करना होगा, जिनकी आवश्यकता नहीं है।
जोहान्स ब्रोडवॉल

11
मुझे लगता है कि प्रदूषण दूसरे तरीके से काम करता है। यदि मुझे डेटा को उत्सुक रूप से लोड करने की आवश्यकता है, तो तर्क परत (या डेटा एक्सेस परत को बदतर) यह जानने की आवश्यकता है कि किसी वस्तु को किस तरीके से प्रदर्शित किया जाना है। दृश्य बदलें और आप उन सामानों को लोड करें जिनकी आपको आवश्यकता नहीं है या जिन्हें आप की आवश्यकता नहीं है। एक हाइबरनेट अपवाद एक बग है और किसी अन्य अप्रत्याशित अपवाद के रूप में विषाक्तता है। लेकिन प्रदर्शन एक मुद्दा है। प्रदर्शन और मापनीयता के मुद्दे आपको अपने डेटा एक्सेस लेयर में अधिक विचार और काम करने के लिए मजबूर करेंगे, और संभवतः सत्र को पहले बंद करने के लिए मजबूर करेंगे
जेन्स स्काउडर

1
@JensSchauder "दृश्य बदलें और आप लोडिंग सामान को समाप्त करते हैं जिसकी आपको आवश्यकता नहीं है या आपको आवश्यक वस्तुएं याद नहीं हैं"। बिलकुल ऐसा ही है। यदि आप दृश्य बदलते हैं, तो सामान को लोड करने के लिए बेहतर है जिसकी आपको आवश्यकता नहीं है (जैसा कि आप उन्हें लाने के लिए उत्सुक होने की अधिक संभावना रखते हैं) या लापता वस्तुओं का पता लगा सकते हैं क्योंकि आपको देखने का भार छोड़ने की तुलना में आलसी लोडिंग अपवाद मिलेगा। यह आलसी के रूप में N + 1 समस्या में परिणाम देगा, और आपको पता भी नहीं होगा कि यह हो रहा है। तो IMO इसकी बेहतर सर्विस लेयर है (और आप) जानते हैं कि इसे देखने से क्या भेजा जाता है जो कि लाज़िली लोड हो रहा है और आप इसके बारे में कुछ नहीं जानते हैं।
जेशुरुन

40

लंबे समय तक वर्णन के लिए, आप मेरे ओपन सेशन इन व्यू एंटी-पैटर्न लेख को पढ़ सकते हैं । अन्यथा, यहां इस बात का सारांश है कि आपको ओपन सेशन इन व्यू का उपयोग क्यों नहीं करना चाहिए।

ओपन सेशन इन व्यू डेटा लाने के लिए एक बुरा तरीका है। व्यापार परत को यह तय करने के बजाय कि व्यू लेयर द्वारा आवश्यक सभी संघों को लाने के लिए यह सबसे अच्छा है, यह दृढ़ता प्रसंग को खुले रहने के लिए मजबूर करता है ताकि व्यू लेयर प्रॉक्सी प्रॉक्सी को ट्रिगर कर सके।

यहां छवि विवरण दर्ज करें

  • OpenSessionInViewFilterकॉल openSessionअंतर्निहित की विधि SessionFactoryऔर एक नया प्राप्त Session
  • के Sessionलिए बाध्य है TransactionSynchronizationManager
  • OpenSessionInViewFilterकॉल doFilterकी javax.servlet.FilterChainवस्तु संदर्भ और अनुरोध आगे संसाधित किया जाता है
  • DispatcherServletकहा जाता है, और अंतर्निहित करने के लिए इसे मार्गों HTTP अनुरोध PostController
  • PostControllerकॉल PostServiceकी एक सूची प्राप्त करने के लिए Postसंस्थाओं।
  • PostServiceएक नई लेन-देन को खोलता है, और HibernateTransactionManagerएक ही पुनः उपयोग कर लेता Sessionहै कि द्वारा खोला गया था OpenSessionInViewFilter
  • PostDAOकी सूची को हासिल करेगा Postकिसी भी आलसी संघ आरंभ बिना संस्थाओं।
  • PostServiceअंतर्निहित लेन-देन करता है, लेकिन Sessionबंद नहीं है, क्योंकि यह बाह्य खोला गया था।
  • DispatcherServletशुरू होता है यूआई, जो, बारी में, आलसी संघों नेविगेट करता है और उनके प्रारंभ से चलाता है प्रतिपादन।
  • OpenSessionInViewFilterबंद कर सकते हैं Session, और अंतर्निहित डेटाबेस कनेक्शन में अच्छी तरह से जारी किया गया है।

पहली नज़र में, यह करने के लिए एक भयानक बात की तरह नहीं लग सकता है, लेकिन, एक बार जब आप इसे डेटाबेस के दृष्टिकोण से देखते हैं, तो दोषों की एक श्रृंखला अधिक स्पष्ट होने लगती है।

सेवा परत डेटाबेस लेनदेन को खोलता और बंद करता है, लेकिन बाद में, कोई स्पष्ट लेनदेन नहीं होता है। इस कारण से, UI रेंडरिंग चरण से जारी किया गया प्रत्येक अतिरिक्त विवरण ऑटो-कम मोड में निष्पादित किया जाता है। ऑटो-कमिट डेटाबेस सर्वर पर दबाव डालता है क्योंकि प्रत्येक स्टेटमेंट में लेन-देन लॉग को डिस्क में फ्लश करना चाहिए, इसलिए डेटाबेस साइड पर बहुत सारे I / O ट्रैफिक का कारण बनता है। एक अनुकूलन के Connectionरूप में केवल पढ़ने के लिए चिह्नित किया जाएगा जो डेटाबेस सर्वर को लेनदेन लॉग में लिखने से बचने की अनुमति देगा।

अब चिंताओं का कोई पृथक्करण नहीं है क्योंकि बयान सेवा परत और UI रेंडरिंग प्रक्रिया दोनों द्वारा उत्पन्न होते हैं। एकीकरण परीक्षण लिखना जो उत्पन्न होने वाले कथनों की संख्या को बढ़ाता है, सभी परतों (वेब, सेवा, डीएओ) के माध्यम से जाने की आवश्यकता होती है, जबकि एक वेब कंटेनर पर तैनात अनुप्रयोग। इन-मेमोरी डेटाबेस (जैसे एचएसक्यूएलडीबी) और एक हल्के वेब सर्वर (जैसे जेट्टी) का उपयोग करते समय भी, इन एकीकरण परीक्षणों को निष्पादित करने की तुलना में धीमी होने जा रही है यदि परतें अलग हो जाती थीं और बैक-एंड एकीकरण परीक्षण डेटाबेस का उपयोग करते थे, जबकि फ्रंट-एंड इंटीग्रेशन टेस्ट पूरी तरह से सर्विस लेयर का मजाक उड़ा रहे थे।

यूआई परत नेविगेट करने वाले संघों तक सीमित है, जो बदले में, एन + 1 क्वेरी समस्याओं को ट्रिगर कर सकती है। यद्यपि हाइबरनेट @BatchSizeबैचों में संघों को लाने के लिए प्रदान करता है , और FetchMode.SUBSELECTइस परिदृश्य का सामना करने के लिए, एनोटेशन डिफ़ॉल्ट रूप से लाने की योजना को प्रभावित कर रहे हैं, इसलिए वे हर व्यवसाय उपयोग के मामले में लागू होते हैं। इस कारण से, डेटा एक्सेस लेयर क्वेरी बहुत अधिक उपयुक्त है, क्योंकि इसे वर्तमान उपयोग के मामले के लिए प्राप्त किया जा सकता है।

अंतिम लेकिन कम से कम, डेटाबेस कनेक्शन पूरे यूआई रेंडरिंग चरण (आपके कनेक्शन रिलीज मोड के आधार पर) पर आयोजित किया जा सकता है जो कनेक्शन के पट्टे के समय को बढ़ाता है और डेटाबेस कनेक्शन पूल पर भीड़ के कारण समग्र लेनदेन को सीमित करता है। जितना अधिक कनेक्शन आयोजित किया जाता है, उतना ही अन्य समवर्ती अनुरोध पूल से कनेक्शन प्राप्त करने के लिए इंतजार करने वाले हैं।

तो, या तो आप बहुत लंबे समय तक कनेक्शन प्राप्त करते हैं, या तो आप एक ही HTTP अनुरोध के लिए कई कनेक्शन प्राप्त करते हैं / जारी करते हैं, इसलिए अंतर्निहित कनेक्शन पूल पर दबाव डालते हैं और स्केलेबिलिटी को सीमित करते हैं।

स्प्रिंग बूट

दुर्भाग्य से, दृश्य में ओपन सत्र स्प्रिंग बूट में डिफ़ॉल्ट रूप से सक्षम है

इसलिए, सुनिश्चित करें कि application.propertiesकॉन्फ़िगरेशन फ़ाइल में, आपके पास निम्न प्रविष्टि है:

spring.jpa.open-in-view=false

यह OSIV को अक्षम कर देगा, ताकि आप सही तरीके से संभालLazyInitializationException सकें ।


3
ऑटो-कमिट के साथ दृश्य में ओपन सत्र का उपयोग करना संभव है, लेकिन यह हाइबरनेट डेवलपर्स द्वारा जिस तरह से इरादा नहीं था। इसलिए यद्यपि ओपन सेशन इन व्यू में अपनी कमियां हैं, ऑटो-कमिट एक नहीं है क्योंकि आप इसे बस बंद कर सकते हैं और अभी भी इसका उपयोग कर सकते हैं।
stefan.m

आप इस बारे में बात कर रहे हैं कि लेन-देन के अंदर क्या होता है, और यह सच है। लेकिन वेब लेयर रेंडरिंग चरण हाइबरनेट के बाहर होता है, इसलिए आपको ऑटोकॉमिट मोड मिलता है। समझ में आता है?
व्लादिमीर मिहालसी

मुझे लगता है कि यह एक ऐसा संस्करण है जो दृश्य में ओपन सत्र के लिए इष्टतम नहीं है। सत्र और लेन-देन तब तक खुला रहना चाहिए जब तक कि दृश्य प्रदान नहीं किया गया है, फिर ऑटोकॉमिट मोड की आवश्यकता नहीं है।
स्टीफन.m

2
सत्र खुला रहता है। लेकिन लेन-देन नहीं करता है। पूरी प्रक्रिया में लेन-देन का विस्तार करना या तो इष्टतम नहीं है क्योंकि इसकी लंबाई बढ़ जाती है और ताले आवश्यकता से अधिक समय तक आयोजित किए जाते हैं। कल्पना कीजिए कि यदि दृश्य एक RuntimeException फेंकता है तो क्या होगा। क्या लेन-देन रोलबैक होगा क्योंकि UI रेंडरिंग विफल हो गई है?
व्लाद मिहालसी 17

बहुत विस्तृत जवाब के लिए बहुत बहुत धन्यवाद! मैं केवल अंत में गाइड बदल दूंगा क्योंकि स्प्रिंग बूट उपयोगकर्ता संभवतः उस तरह से jpa का उपयोग नहीं करेंगे।
स्कीव

24
  • लेनदेन सेवा परत में किए जा सकते हैं - लेनदेन OSIV से संबंधित नहीं हैं। यह है Sessionकि खुला रहता है, लेनदेन नहीं - चल रहा है।

  • यदि आपकी एप्लिकेशन परतें कई मशीनों में फैली हुई हैं, तो आप बहुत अधिक OSIV का उपयोग नहीं कर सकते हैं - आपको ऑब्जेक्ट को तार पर भेजने से पहले अपनी जरूरत की सभी चीजों को इनिशियलाइज़ करना होगा।

  • OSIV एक अच्छा और पारदर्शी है (यानी - आपके किसी भी कोड को पता नहीं है कि ऐसा होता है) लैक लोडिंग के प्रदर्शन लाभों का उपयोग करने का तरीका


2
पहले बुलेट बिंदु के बारे में, यह जेबीओस विकी से मूल OSIV के लिए कम से कम सच नहीं है , यह अनुरोध के आसपास लेनदेन सीमांकन को भी संभालता है।
पास्कल थिवेंट

@PascalThivent आपको कौन सा हिस्सा ऐसा लगता है?
सांग्युन ली जुले

13

मैं यह नहीं कहूंगा कि ओपन सेशन इन व्यू को एक बुरा अभ्यास माना जाता है; वह धारणा क्या है?

ओपन-सेशन-इन-व्यू हाइबरनेट के साथ सत्र को संभालने का एक सरल तरीका है। क्योंकि यह सरल है, यह कभी-कभी सरल है। यदि आपको अपने लेन-देन पर ठीक-ठाक नियंत्रण की आवश्यकता है, जैसे कि एक अनुरोध में कई लेनदेन करना, ओपन-सेशन-इन-व्यू हमेशा एक अच्छा दृष्टिकोण नहीं है।

जैसा कि दूसरों ने बताया है, OSIV के लिए कुछ ट्रेड-ऑफ हैं - आप N + 1 समस्या से बहुत अधिक ग्रस्त हैं क्योंकि आपको यह एहसास होने की संभावना कम है कि आप किस लेनदेन को किक मार रहे हैं। उसी समय, इसका मतलब है कि आपको अपने दृश्य में मामूली बदलावों के अनुकूल होने के लिए अपनी सेवा परत को बदलने की आवश्यकता नहीं है।


5

यदि आप स्प्रिंग जैसे नियंत्रण (IoC) कंटेनर का उलटा उपयोग कर रहे हैं, तो आप बीन स्कूपिंग पर पढ़ना चाह सकते हैं । अनिवार्य रूप से, मैं स्प्रिंग को मुझे एक हाइबरनेट Sessionऑब्जेक्ट देने के लिए कह रहा हूं जिसका जीवन चक्र पूरे अनुरोध को फैलाता है (यानी, यह HTTP अनुरोध के प्रारंभ और अंत में निर्मित और नष्ट हो जाता है)। मुझे इस बारे में चिंता करने की ज़रूरत नहीं है LazyLoadExceptionऔर न ही सत्र को बंद करना है क्योंकि आईओसी कंटेनर मेरे लिए प्रबंधन करता है।

जैसा कि उल्लेख किया गया है, आपको एन + 1 चयन प्रदर्शन के मुद्दों के बारे में सोचना होगा। आप हमेशा अपने हाइबरनेट इकाई को बाद में कॉन्फ़िगर कर सकते हैं ताकि उन जगहों पर उत्सुकता से लोडिंग कर सकें जहां प्रदर्शन एक मुद्दा है।

बीन स्कूपिंग सॉल्यूशन स्प्रिंग-स्पेसिफिक नहीं है। मुझे पता है कि PicoContainer समान क्षमता प्रदान करता है और मुझे यकीन है कि अन्य परिपक्व IoC कंटेनर कुछ इसी तरह की पेशकश करते हैं।


1
क्या आपके पास हाइपरनेट सत्रों के वास्तविक कार्यान्वयन के लिए एक संकेतक है जिसे अनुरोधित सेम के माध्यम से दृश्य में उपलब्ध कराया जा रहा है?
मर्वो

4

मेरे अपने अनुभव में, OSIV इतना बुरा नहीं है। एकमात्र व्यवस्था जो मैंने की है वह दो अलग-अलग लेनदेन का उपयोग कर रही है: - पहला, "सर्विस लेयर" में खोला गया, जहाँ मेरे पास "व्यावसायिक तर्क" है - दूसरा दृश्य प्रतिपादन से ठीक पहले खोला गया


3

मैंने अभी कुछ दिशानिर्देशों पर एक पोस्ट किया है कि अपने ब्लॉग में दृश्य में खुले सत्र का उपयोग कब किया जाए। अगर आपकी रुचि है तो इसे देखें।

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


1
अंगूठे के एक सामान्य एसओ नियम के रूप में, यदि आप एक उत्तर प्रदान कर रहे हैं, तो यह कहीं और लिंक से अधिक करने के लिए सबसे अच्छा है। शायद एक या दो वाक्य या सूचीबद्ध आइटम प्रदान करते हैं। लिंक करना ठीक है, लेकिन आप थोड़ा अतिरिक्त मूल्य प्रदान करना चाहते हैं। अन्यथा, आप केवल टिप्पणी करना चाहते हैं और वहां लिंक डाल सकते हैं।
DWright

इस जवाब में लिंक लायक पढ़ने, यह जब OSIV का उपयोग करने पर एक अच्छा मार्गदर्शन प्रदान करता है और नहीं है
एम्स

1

मैं हाइबरनेट पर वी। रस्टी हूं .. लेकिन मुझे लगता है कि एक हाइबरनेट सत्र में इसके कई लेन-देन संभव हैं। इसलिए आपकी लेन-देन की सीमाएँ सत्र प्रारंभ / रुकने की घटनाओं के समान नहीं होनी चाहिए।

OSIV, imo, मुख्य रूप से उपयोगी है, क्योंकि हम हर बार अनुरोध 'DB' बनाने के लिए 'हठ प्रसंग' (उर्फ सत्र) शुरू करने के लिए कोड लिखने से बच सकते हैं।

आपकी सेवा की परत में, आपको संभवतः उन तरीकों से कॉल करने की आवश्यकता होगी, जिनमें अलग-अलग लेनदेन की ज़रूरतें होती हैं, जैसे कि 'आवश्यक, नया आवश्यक, आदि।' इन विधियों की आवश्यकता केवल यह है कि किसी ने (यानी OSIV फ़िल्टर) दृढ़ता संदर्भ शुरू कर दिया है, ताकि केवल एक चीज के बारे में उन्हें चिंता करनी पड़े - "हे मुझे इस थ्रेड के लिए हाइबरनेट सत्र दें .. मुझे कुछ करने की ज़रूरत है DB सामान ”।


1

यह बहुत मदद नहीं करेगा, लेकिन आप यहां मेरे विषय की जांच कर सकते हैं: * Hibernate Cache1 OutOfMemory के साथ OpenessionInView

OpenSessionInView और लोड की गई बहुत सारी संस्थाओं के कारण मेरे पास कुछ आउटऑफ़मेरी समस्याएँ हैं, क्योंकि वे हाइबरनेट कैश स्तर 1 में रहते हैं और कचरा एकत्र नहीं किए जाते हैं (मैं प्रति पृष्ठ 500 वस्तुओं के साथ बहुत सारी संस्थाओं को लोड करता हूं, लेकिन सभी कैश में रहते हैं)

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.