2009-03-10 11 views
12

के साथ एनएचबर्ननेट थ्रेड सुरक्षा अब मैं कुछ समय से एनएचबीरनेट का उपयोग कर रहा हूं और समय-समय पर पाया है कि यदि मैं दो पृष्ठों को एक साथ अनुरोध करने का प्रयास करता हूं (या जितना करीब हो सकता है) तो यह कभी-कभी त्रुटि होगी। इसलिए मैंने माना कि ऐसा इसलिए था क्योंकि मेरा सत्र प्रबंधन थ्रेड सुरक्षित नहीं था।सत्र

मैंने सोचा कि यह मेरी कक्षा थी इसलिए मैंने इस ब्लॉग पोस्ट http://pwigle.wordpress.com/2008/11/21/nhibernate-session-handling-in-aspnet-the-easy-way/ से एक अलग विधि का उपयोग करने की कोशिश की, हालांकि मुझे अभी भी वही समस्याएं मिलती हैं। वास्तविक त्रुटि मैं हो रही है:

Server Error in '/AvvioCMS' Application. 
failed to lazily initialize a collection, no session or session was closed 
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 

Exception Details: NHibernate.LazyInitializationException: failed to lazily initialize a collection, no session or session was closed 

या तो उस या नहीं DataReader खुला है, लेकिन यह मुख्य दोषी है।

मैंने अपना सत्र प्रबंधन वर्ग नीचे रखा है, क्या कोई यह बता सकता है कि मुझे इन मुद्दों का सामना क्यों हो रहा है?

public interface IUnitOfWorkDataStore 
{ 
    object this[string key] { get; set; } 
} 


    public static Configuration Init(IUnitOfWorkDataStore storage, Assembly[] assemblies) 
    { 
     if (storage == null) 
      throw new Exception("storage mechanism was null but must be provided"); 

     Configuration cfg = ConfigureNHibernate(string.Empty); 
     foreach (Assembly assembly in assemblies) 
     { 
      cfg.AddMappingsFromAssembly(assembly); 
     } 

     SessionFactory = cfg.BuildSessionFactory(); 
     ContextDataStore = storage; 

     return cfg; 
    } 

    public static ISessionFactory SessionFactory { get; set; } 
    public static ISession StoredSession 
    { 
     get 
     { 
      return (ISession)ContextDataStore[NHibernateSession.CDS_NHibernateSession]; 
     } 
     set 
     { 
      ContextDataStore[NHibernateSession.CDS_NHibernateSession] = value; 
     } 
    } 

    public const string CDS_NHibernateSession = "NHibernateSession"; 
    public const string CDS_IDbConnection = "IDbConnection"; 

    public static IUnitOfWorkDataStore ContextDataStore { get; set; } 

    private static object locker = new object(); 
    public static ISession Current 
    { 
     get 
     { 
      ISession session = StoredSession; 

      if (session == null) 
      { 
       lock (locker) 
       { 
        if (DBConnection != null) 
         session = SessionFactory.OpenSession(DBConnection); 
        else 
         session = SessionFactory.OpenSession(); 

        StoredSession = session; 
       } 
      } 

      return session; 
     } 
     set 
     { 
      StoredSession = value; 
     } 
    } 

    public static IDbConnection DBConnection 
    { 
     get 
     { 
      return (IDbConnection)ContextDataStore[NHibernateSession.CDS_IDbConnection]; 
     } 
     set 
     { 
      ContextDataStore[NHibernateSession.CDS_IDbConnection] = value; 
     } 
    } 

} 

और वास्तविक दुकान मैं उपयोग कर रहा हूँ यह है:

public class HttpContextDataStore : IUnitOfWorkDataStore 
{ 
    public object this[string key] 
    { 
     get { return HttpContext.Current.Items[key]; } 
     set { HttpContext.Current.Items[key] = value; } 
    } 
} 

मैं साथ Application_Start पर SessionFactory प्रारंभ:

NHibernateSession.Init(new HttpContextDataStore(), new Assembly[] { 
       typeof(MappedClass).Assembly}); 

अद्यतन

हाय दोस्तों, आपकी सलाह के लिए धन्यवाद, मैंने कुछ अलग करने की कोशिश की है कोड को आज़माने और सरल बनाने के लिए चीजें हैं लेकिन मैं अभी भी एक ही मुद्दे पर चल रहा हूं और मुझे एक विचार हो सकता है कि क्यों।

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

किसी को भी कोई विचार है? मैंने एक गूगल किया और देखा कि वीएस विकास सर्वर इस तरह के मुद्दों का कारण बनता है लेकिन मैं इसे आईआईएस के माध्यम से चला रहा हूं।

उत्तर

24

जबकि मैंने आपका संपूर्ण कोडबेस या समस्या को हल करने की कोशिश नहीं की है, तो आप एनएचबर्ननेट का उपयोग करने के तरीके की पुनर्विचार कर सकते हैं।documentation से:

  • कभी डेटाबेस कनेक्शन प्रति एक से अधिक समवर्ती ISession या ITransaction उदाहरण बनाने के लिए:

    आप NHibernate सत्र बनाते समय निम्न प्रथाओं का पालन करना चाहिए।

  • प्रति लेनदेन प्रति डेटाबेस एक से अधिक ISession बनाते समय बेहद सावधान रहें। ISession स्वयं लोड ऑब्जेक्ट्स को लोड किए गए अपडेट का ट्रैक रखता है, इसलिए एक अलग ISession पुराना डेटा देख सकता है।

  • ISession थ्रेडसेफ नहीं है! कभी दो समवर्ती धागे में एक ही ISession तक पहुंचें। एक ISession आमतौर पर केवल एकल यूनिट-ऑफ-वर्क है!

पिछले बिट है कि मैं क्या कह रहा हूँ करने के लिए सबसे अधिक प्रासंगिक (और एक बहु-क्रम पर्यावरण के मामले में महत्वपूर्ण)। एक छोटे से परमाणु संचालन के लिए एक आइसिया का इस्तेमाल किया जाना चाहिए और फिर निपटान किया जाना चाहिए। दस्तावेज़ से भी:

एक ISessionFactory है एक महंगा करने के लिए बनाने के लिए, threadsafe वस्तु सभी आवेदन धागे द्वारा साझा किया जा करने का इरादा। एक ISession एक सस्ती, गैर-थ्रेडसेफ ऑब्जेक्ट है जिसे एक बार व्यवसाय प्रक्रिया के लिए उपयोग किया जाना चाहिए, और फिर त्याग दिया जाना चाहिए।

आईएसओशन को स्वयं संग्रहित करने के बजाय उन दो विचारों को जोड़कर, सत्र कारखाने को स्टोर करें क्योंकि यह "बड़ी" वस्तु है। फिर सत्र सत्र से फैक्ट्री को पुनर्प्राप्त करने और सत्र को तुरंत चालू करने और इसे एक ऑपरेशन के लिए उपयोग करने के लिए आप एक रैपर के रूप में SessionManager.GetSession() जैसे कुछ कार्य कर सकते हैं।

समस्या एएसपी.NET अनुप्रयोग के संदर्भ में भी कम स्पष्ट है। आप स्थिर रूप से ISession ऑब्जेक्ट को स्कॉप कर रहे हैं जिसका अर्थ है कि इसे ऐपडोमेन में साझा किया गया है। यदि उस ऐपडोमेन के जीवनकाल में दो अलग-अलग पृष्ठ अनुरोध बनाए जाते हैं और एक साथ निष्पादित किए जाते हैं, तो आपके पास एक ही ISession को छूने वाले दो पृष्ठ (विभिन्न धागे) हैं जो सुरक्षित नहीं हैं।

असल में, जितना संभव हो सके एक सत्र को रखने की कोशिश करने के बजाय, जितनी जल्दी हो सके उनसे छुटकारा पाने का प्रयास करें और देखें कि आपके पास बेहतर परिणाम हैं या नहीं।

संपादित करें:

ठीक है, मैं देख सकता हूँ तुम कहाँ इस के साथ जाने के लिए कोशिश कर रहे हैं। ऐसा लगता है कि आप ओपन सत्र इन व्यू पैटर्न को कार्यान्वित करने की कोशिश कर रहे हैं, और वहां कुछ अलग-अलग मार्ग हैं जिन्हें आप ले सकते हैं:

यदि कोई अन्य ढांचा जोड़ना कोई मुद्दा नहीं है, तो Spring.NET जैसे कुछ देखें। यह मॉड्यूलर है इसलिए आपको पूरी चीज का उपयोग करने की ज़रूरत नहीं है, आप केवल NHibernate सहायक मॉड्यूल का उपयोग कर सकते हैं।यह दृश्य पैटर्न में खुले सत्र का समर्थन करता है। दस्तावेज़ीकरण here (शीर्षक 21.2.10। "वेब सत्र प्रबंधन")।

यदि आप अपना खुद का रोल करना चाहते हैं, तो बिल मैककैफ़र्टी द्वारा इस कोडप्रोजेक्ट पोस्टिंग को देखें: "NHibernate Best Practices"। अंत में वह एक कस्टम IHttpModule के माध्यम से पैटर्न को लागू करने का वर्णन करता है। मैंने आईएचटीपी मॉड्यूल के बिना पैटर्न को लागू करने के लिए इंटरनेट के चारों ओर पोस्ट भी देखी हैं, लेकिन हो सकता है कि आप जो भी कोशिश कर रहे हैं।

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

+0

धन्यवाद स्टुअर्ट, मैं केवल तब तक सत्र रखने की कोशिश कर रहा हूं जब तक पृष्ठ का अनुरोध ज़िंदा है, जिसे मैंने सोचा होगा कि काफी कम है? मैं हर डीबी कॉल के लिए सत्र बनाने का प्रयास कर सकता हूं लेकिन यह मुझे थोड़ा भारी लगता है? –

+1

ठीक है, मैं देखता हूं कि आप इसके साथ कहां जा रहे हैं। संपादन देखें। हालांकि, एक साइड नोट के रूप में, जैसा कि मैंने आईएसएशन को स्थैतिक अर्थ घोषित करने का उल्लेख किया है, यह एक पृष्ठ अनुरोध (शायद) से अधिक समय तक टिकेगा। –

+0

@StuartChilds क्या आप मुझे किसी भी IHttpModule के बिना कार्यान्वयन के लिए इंगित कर सकते हैं? इसके अलावा आप लेनदेन का प्रबंधन कैसे करते हैं और सत्रों को बंद/बंद करते हैं? – Rahatur

2

मैं एनएचबेर्नेट में निश्चित नहीं हो सकता (क्योंकि मैं जावा हाइबरनेट लड़का हूं) लेकिन हाइबरनेट सत्र ऑब्जेक्ट्स डिज़ाइन द्वारा थ्रेड सुरक्षित नहीं हैं। आपको एक सत्र खोलना और बंद करना चाहिए और इसे वर्तमान धागे के दायरे से बाहर नहीं जाने देना चाहिए।

मुझे यकीन है कि 'ओपन सत्र दृश्य' जैसे पैटर्न कहीं भी नेट में लागू किए गए हैं।

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

उम्मीद है कि इससे मदद मिलती है। गैरेथ

1

समस्या यह साबित हुई कि नियंत्रण के विचलन के लिए मेरी लाइब्रेरी HTTP संदर्भ में बनाई गई वस्तुओं को सही ढंग से प्रबंधित नहीं कर रही थी इसलिए मुझे उन संदर्भों के संदर्भ मिल रहे थे जो उस संदर्भ में उपलब्ध नहीं होनी चाहिए। यह निंजा 1.0 का उपयोग कर रहा था, एक बार जब मैंने निनजेक्ट 2.0 (बीटा) में अपडेट किया तो समस्या हल हो गई।