2009-12-20 9 views
8

वर्तमान में हमारे पास एक स्टेटलेट बीन है जिसे सर्वलेट में इंजेक्शन दिया जाता है। समस्या यह है कि कभी-कभी हमें राज्य के बीन पर एक विधि निष्पादित करते समय Caused by: javax.ejb.ConcurrentAccessException: SessionBean is executing another request. [session-key: 7d90c02200a81f-752fe1cd-1] मिलता है।Servlets के साथ राज्यिक बीन्स का सही उपयोग

public class NewServlet extends HttpServlet { 
    @EJB 
    private ReportLocal reportBean; 

    protected void processRequest(HttpServletRequest request, HttpServletResponse response) 
    throws ServletException, IOException { 
     response.setContentType("text/html;charset=UTF-8"); 
     PrintWriter out = response.getWriter(); 
     try { 
      String[] parameters = fetchParameters(request); 
      out.write(reportBean.constructReport(parameters)); 
     } finally { 
      out.close(); 
     } 
    } 
} 

उपरोक्त कोड में, constructReport जाँच करेगा कि क्या यह डेटाबेस की रिपोर्ट में निर्दिष्ट जिसके बाद HTML में एक रिपोर्ट एक प्रश्न जो निर्दिष्ट मापदंडों से बनाया गया है से निर्माण किया है के लिए एक नया कनेक्शन खोलने की जरूरत है।

एक स्टेटलेस बीन पर एक राज्यव्यापी बीन का उपयोग करने का कारण हमने क्यों चुना क्योंकि हमें अज्ञात डेटाबेस में डेटाबेस कनेक्शन खोलने और इसके बारे में प्रश्न करने की आवश्यकता है। एक स्टेटलेस बीन के साथ यह बीन के प्रत्येक इंजेक्शन उदाहरण के साथ बार-बार डेटाबेस कनेक्शन को खोलने और बंद करने के लिए बहुत अक्षम है।

उत्तर

9

यह नहीं है कि राज्यव्यापी सत्र बीन्स (एसएफएसबी) का उपयोग किस उद्देश्य के लिए किया जाना है। उन्हें वार्तालाप स्थिति रखने के लिए डिज़ाइन किया गया है, और उस स्थिति को पकड़ने के लिए उपयोगकर्ता के http सत्र से बाध्य होना है, जैसे सत्र में राज्य को संग्रहीत करने के लिए हेवीवेट विकल्प।

यदि आप डेटाबेस कनेक्शन जैसी चीजें रखना चाहते हैं, तो इसके बारे में जाने के बेहतर तरीके हैं।

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

+0

AFAIK, एक ऐपसेवर पर डेटासॉर्स बनाते समय आपको हाथ से पहले पता होना चाहिए कि डेटाबेस मौजूद है। उपरोक्त कनेक्शन डेटाबेस में बनाया गया है जिसे उपयोगकर्ता निर्दिष्ट करता है जिसे हमें कनेक्ट करना होगा। – Burmudar

+3

यह मेरे लिए बहुत असुरक्षित लगता है। – duffymo

1

जब तक आप कुछ कोड और स्टैकट्रैक प्रदान नहीं करते हैं, तो मैं सुझाव दूंगा कि आप connection pool का उपयोग करने पर विचार करें। यदि "अज्ञात डेटाबेस" से आपका मतलब डेटाबेस है जिसका पैरामीटर अंतिम उपयोगकर्ता द्वारा प्रदान किया जाता है, और इसलिए कोई पूर्व-कॉन्फ़िगर किए गए कनेक्शन पूल संभव नहीं है, तो भी आप हर बार एक नया कनेक्शन खोलने के बजाय कनेक्शन पूल अवधारणा का उपयोग कर सकते हैं।

इसके अलावा, this thread

0

सत्र बीन्स का एक साथ उपयोग नहीं किया जा सकता है, जैसे स्काफमैन ने कहा कि वे क्लाइंट सत्र से संबंधित राज्य को संभालने के लिए थे और आमतौर पर प्रति क्लाइंट सत्र ऑब्जेक्ट में संग्रहीत होते हैं।

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

इस बीच, अगर आप सभी की जरूरत इस तुच्छ इस्तेमाल होता है, तो आप के रूप में constructReport करने के लिए कॉल को सिंक्रनाइज़ कर सकते हैं:

synchronised (reportBean) { 
     out.write(reportBean.constructReport(parameters)); 
} 

ध्यान दें कि यह कोई समाधान नहीं है अगर constructReport के लिए समय रिश्तेदार की एक महत्वपूर्ण राशि ले जाता है आपके ग्राहकों की संख्या।

14

ConcurrentAccessException के बारे में कुछ और विवरण: ईजेबी स्पेक के अनुसार, एसएलएसबी तक पहुंच ऐप द्वारा सिंक्रनाइज़ की जाती है। सर्वर। हालांकि, यह एसएफएसबी के साथ मामला नहीं है। यह सुनिश्चित करने का बोझ है कि एसएफएसबी को समवर्ती रूप से एक्सेस नहीं किया गया है, एप्लिकेशन डेवलपर के कंधों पर है।

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

इसका मतलब है कि सर्वलेट से एसएफएसबी का उपयोग करना जटिल है। एक ही सत्र से कई खिड़कियों वाले उपयोगकर्ता, या रेंडरिंग समाप्त होने से पहले पृष्ठ को पुनः लोड करने से समवर्ती पहुंच हो सकती है। सर्वलेट में किए गए ईजेबी की प्रत्येक पहुंच सैद्धांतिक रूप से बीन पर सिंक्रनाइज़ करने की आवश्यकता होती है। क्या मैंने किया था विशेष EJB उदाहरण पर सभी आमंत्रण सिंक्रनाइज़ करने के लिए एक InvocationHandler बनाने के लिए किया गया था: तब

public class SynchronizationHandler implements InvocationHandler { 

private Object target; // the EJB 

public SynchronizationHandler(Object bean) 
{ 
     target = bean; 
} 

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable 
    { 
    synchronized(target) 
    { 
     // invoke method to the target EJB 
    } 
    } 

}

, सही होने के बाद आप EJB के लिए दूरदराज के संदर्भ प्राप्त है, आप इसे SynchronizationHandler के साथ रैप । इस तरह आप सुनिश्चित हैं कि इस विशेष उदाहरण को आपके ऐप से समवर्ती रूप से एक्सेस नहीं किया जाएगा (जब तक यह केवल एक JVM में चलता है)। आप एक नियमित रैपर वर्ग भी लिख सकते हैं जो बीन के सभी तरीकों को सिंक्रनाइज़ करता है।

मेरा निष्कर्ष फिर भी है: जब भी संभव हो एसएलएसबी का उपयोग करें।

संपादित:

इस उत्तर EJB 3.0 चश्मा को दर्शाता है (अनुभाग 4.3.13):

ग्राहकों स्टेटफुल सत्र के लिए समवर्ती कॉल वस्तु बनाने के लिए अनुमति नहीं है। यदि उदाहरण पर क्लाइंट-चालान व्यवसाय विधि प्रगति पर है, तो एक और क्लाइंट-आह्वान कॉल, एक ही या अलग क्लाइंट से, एक राज्य सत्र सत्र बीन क्लास, के उसी उदाहरण पर आता है यदि दूसरा क्लाइंट क्लाइंट है सेम के व्यापार इंटरफेस, समवर्ती मंगलाचरण javax.ejb.ConcurrentAccessException

इस तरह के प्रतिबंध EJB 3.1 में हटा दिया गया है (खंड 4.3.13) प्राप्त दूसरा ग्राहक में हो सकता है:

डिफ़ॉल्ट रूप से, ग्राहकों को बनाने की अनुमति है समसामयिक सत्र ऑब्जेक्ट के समवर्ती कॉल और कंटेनर को समवर्ती अनुरोधों को क्रमबद्ध करने की आवश्यकता है।

[...]

बीन डेवलपर वैकल्पिक रूप से निर्दिष्ट कर सकता है कि समवर्ती ग्राहक स्टेटफुल सत्र सेम को अनुरोध निषिद्ध हैं। यह @AccessTimeout एनोटेशन या एक्सेस-टाइमआउट परिनियोजन डिस्क्रिप्टर तत्व 0 के मान के साथ प्रयोग किया जाता है। इस मामले में, यदि क्लाइंट द्वारा लागू व्यवसाय विधि किसी उदाहरण पर प्रगति पर है, तो जब कोई अन्य क्लाइंट-आह्वान कॉल, से एक ही या अलग क्लाइंट, राज्य सत्र सत्र बीन के उसी उदाहरण पर आता है, यदि दूसरा क्लाइंट बीन के व्यावसायिक इंटरफ़ेस या नो-इंटरफ़ेस व्यू का क्लाइंट है, समवर्ती आमंत्रण का परिणाम दूसरे क्लाइंट को प्राप्त करना होगा javax.ejb।ConcurrentAccessException

+0

ठीक है जब आप जेएनडीआई लुकअप के माध्यम से एसएफएसबी के संदर्भ प्राप्त करने के बाद सिंक्रनाइज़ेशन की आवश्यकता नहीं है, है ना? इस मामले में जावा ईई स्पेक गारंटी देता है कि प्रत्येक लुकअप के लिए एसएफएसबी का एक नया उदाहरण लौटा दिया जाता है। – fnt

+0

@fnt प्रति लुकअप एक नया उदाहरण लौटाया गया है, लेकिन आप इसके साथ क्या करते हैं। कंटेनर उदाहरण के लिए आमंत्रणों को क्रमबद्ध नहीं करेगा, और यदि आप परवाह नहीं करते हैं तो आप एक ConcurrentAccessException के साथ समाप्त कर सकते हैं। – ewernli

+0

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

0

आप इस कारण अनुरोध कतार के बाद से सर्वलेट या EJB पहुँच syncronize कभी नहीं करना चाहिए और यदि आप एन है समवर्ती उपयोगकर्ताओं पिछले एक लंबे समय के लिए इंतजार करेंगे और अक्सर एक समय समाप्ति प्रतिक्रिया मिल !!! सिंक्रनाइज़ेशन विधि इस कारण से नहीं है !!!