2011-09-27 15 views
9

ऐसा लगता है कि NHibernate ADO.NET डेटाबेस कनेक्शन को पूल नहीं करता है। कनेक्शन केवल तभी बंद होते हैं जब लेनदेन किया जाता है या वापस लुढ़का जाता है। स्रोत कोड की एक समीक्षा से पता चलता है कि एनएचबीर्नेट को कॉन्फ़िगर करने का कोई तरीका नहीं है ताकि ISession का निपटारा होने पर कनेक्शन बंद हो जाए।एनएचबेर्नेट और एडीओ.NET कनेक्शन पूलिंग

इस व्यवहार का उद्देश्य क्या था? ADO.NET में कनेक्शन पूलिंग है। लेनदेन के भीतर हर समय उन्हें खोलने की जरूरत नहीं है। इस व्यवहार के साथ भी अनचाहे वितरित लेनदेन बनाए गए हैं। http://davybrion.com/blog/2010/05/avoiding-leaking-connections-with-nhibernate-and-transactionscope/ में वर्णित एक संभावित कार्यवाही इसलिए काम नहीं करती है (कम से कम NHibernate 3.1.0 के साथ नहीं)। मैं इनफॉर्मिक्स का उपयोग कर रहा हूँ। एक ही समस्या हर दूसरे डेटाबेस (NHibernate Connection Pooling) के लिए exisit लगता है।

क्या इस समस्या से परहेज कोई अन्य कामकाज या सलाह है?

यहाँ समस्या उत्पन्न होने एक इकाई परीक्षण है:

[Test] 
    public void DoesNotCloseConnection() 
    { 
    using (SessionFactoryCache sessionFactoryCache = new SessionFactoryCache()) 
    { 
     using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions() { IsolationLevel = IsolationLevel.ReadCommitted, Timeout = TimeSpan.FromMinutes(10) })) 
     { 
      fixture.Setup(); // Creates test data 

      System.Data.IDbConnection connectionOne; 
      System.Data.IDbConnection connectionTwo; 

      using (ISessionFactory sessionFactory = sessionFactoryCache.CreateFactory(GetType(), new TestNHibernateConfigurator())) 
      { 
       using (ISession session = sessionFactory.OpenSession()) 
       { 
       var result = session.QueryOver<Library>().List<Library>(); 
       connectionOne = session.Connection; 
       } 
      } 

      // At this point the first IDbConnection used internally by NHibernate should be closed 

      using (ISessionFactory sessionFactory = sessionFactoryCache.CreateFactory(GetType(), new TestNHibernateConfigurator())) 
      { 
       using (ISession session = sessionFactory.OpenSession()) 
       { 
       var result = session.QueryOver<Library>().List<Library>(); 
       connectionTwo = session.Connection; 
       } 
      } 

      // At this point the second IDbConnection used internally by NHibernate should be closed 

      // Now two connections are open because the transaction is still running 
      Assert.That(connectionOne.State, Is.EqualTo(System.Data.ConnectionState.Closed)); // Fails because State is still 'Open' 
      Assert.That(connectionTwo.State, Is.EqualTo(System.Data.ConnectionState.Closed)); // Fails because State is still 'Open' 
     } 
    } 
    } 

NHibernate-सत्र के निपटान कुछ नहीं करता है के बाद से हम एक सौदे में अभी भी

SessionImpl.cs:

public void Dispose() 
    { 
     using (new SessionIdLoggingContext(SessionId)) 
     { 
      log.Debug(string.Format("[session-id={0}] running ISession.Dispose()", SessionId)); 
      if (TransactionContext!=null) 
      { 
       TransactionContext.ShouldCloseSessionOnDistributedTransactionCompleted = true; 
       return; 
      } 
      Dispose(true); 
     } 
    } 

कस्टम कनेक्शन प्रदाता को इंजेक्शन करना भी काम नहीं करेगा क्योंकि कनेक्शन प्रबंधक को कनेक्शन प्रबंधक को कॉल करने के लिए कई पूर्व शर्तएं हैं जो जांच कर रही हैं कि कनेक्शन को बंद करना लेनदेन की अनुमति नहीं है।

ConnectionManager.cs:

public IDbConnection Disconnect() { 
     if (IsInActiveTransaction) 
      throw new InvalidOperationException("Disconnect cannot be called while a transaction is in progress."); 

     try 
     { 
      if (!ownConnection) 
      { 
       return DisconnectSuppliedConnection(); 
      } 
      else 
      { 
       DisconnectOwnConnection(); 
       ownConnection = false; 
       return null; 
      } 
     } 
     finally 
     { 
      // Ensure that AfterTransactionCompletion gets called since 
      // it takes care of the locks and cache. 
      if (!IsInActiveTransaction) 
      { 
       // We don't know the state of the transaction 
       session.AfterTransactionCompletion(false, null); 
      } 
     } 
    } 
+0

जहाँ तक मुझे पता है, डेटाबेस लेन-देन का उपयोग करने में एक ही कनेक्शन की जरूरत है। तो मुझे यह अजीब नहीं लगता है कि जब तक लेनदेन चल रहा है तब तक यह एक कनेक्शन जीवित रहता है? यदि कनेक्शन पूल में वापस कर दिया गया है, तो ऐसा कुछ भी नहीं है जो सुनिश्चित करता है कि आपको दूसरी बार पूल से एक ही कनेक्शन प्राप्त होगा। – jishi

+0

हालांकि, आपके ठोस परीक्षण में, आप अंतर्निहित आईडीबीकनेक्शन की जांच कर रहे हैं, जो मुझे लगता है कि एडीओ.NET का हिस्सा है, और क्या यह एडीओ.NET कनेक्शन पूलिंग नहीं है जिसे आप उस मामले में परीक्षण कर रहे हैं? आपको क्या करना चाहिए दो अलग-अलग सत्र (उसी फैक्ट्री से भी, सुनिश्चित करें कि यह मामला है) और सुनिश्चित करें कि आपको एक ही कनेक्शन प्राप्त हो। – jishi

+0

प्रत्येक लेनदेन की शुरुआत में चालक वर्ग (मेरे मामले में OdbcDriver) एक नया डीबीकनेक्शन (ओडीबीसी कनेक्शन) बनाता है। यह कनेक्शन पूरे लेनदेन को खोलता है जो अनावश्यक है। मैंने जो परीक्षण लिखा है वह वास्तव में एक सत्र फैक्ट्री से दो अलग-अलग सत्रों का उपयोग करता है। – Antineutrino

उत्तर

8

NHibernate दो "मोड" है।

  • या तो आप अपने आवेदन में कनेक्शन खोलने, तो यह यह प्रबंधित करने की सुविधा पर निर्भर है। sessionfactory.OpenSession(connection) से कनेक्शन पास करते समय यह "मोड" उपयोग किया जाता है।
  • या कनेक्शन एनएच द्वारा बनाया गया है। फिर सत्र बंद होने पर यह बंद हो जाता है। यह "मोड" जब sessionfactory.OpenSession()

से कनेक्शन TransactionScope के लिए कुछ समर्थन नहीं है गुजर नहीं किया जाता है। यह शायद सबसे पहले "मोड" का उपयोग कर रहा है। शायद कनेक्शन एनएच द्वारा नहीं रखा जाता है, लेकिन लेनदेन के दायरे से। मैं बिल्कुल नहीं जानता, मैं पर्यावरण लेनदेन का उपयोग नहीं करता हूं।

एनएच जिस तरह से ADO.NET कनेक्शन पूल का उपयोग कर रहा है।

आप ISession.Disconnect() का उपयोग करके सत्र को डिस्कनेक्ट भी कर सकते हैं और ISession.Reconnect() का उपयोग करके पुनः कनेक्ट कर सकते हैं।

में documentation आप पाते हैं:

विधि ISession.Disconnect() ADO.NET कनेक्शन से सत्र बाधित हो और पूल (जब तक आप कनेक्शन प्रदान की गई) के लिए कनेक्शन वापस आ जाएगी।

+1

आपके उत्तर के लिए धन्यवाद लेकिन मुझे लगता है कि आप "दूसरे" मोड में गलत हैं।जब सत्र का निपटारा किया जाता है तो कनेक्शन खुला रहता है। जैसा कि आप ऊपर पोस्ट किए गए कोड में देख सकते हैं (ConnectionManager.cs) लेनदेन के दायरे में डिस्कनेक्ट/रीकनेक्ट करना संभव नहीं है। आपके द्वारा प्रदान किए गए लिंक में यह भी कहा जाता है कि आप फिर से डिस्कनेक्ट/पुनः कनेक्ट करने से पहले लेनदेन को प्रतिबद्ध/निरस्त करना होगा। कनेक्शन (आईडीबीकनेक्शन) को कनेक्शन प्रबंधक श्रेणी द्वारा निजी सदस्य के रूप में नियंत्रित किया जाता है, न कि लेनदेन द्वारा। – Antineutrino

0

आप अपनी कनेक्शन स्ट्रिंग में निम्न सेटिंग्स जोड़कर इसे पूरा कर सकते हैं।

Pooling=true; 
Min Pool Size=3; 
Max Pool Size=25; 
Connection Lifetime=7200; 
Connection Timeout=15; 
Incr Pool Size=3; 
Decr Pool Size=5; 

पूलिंग: अपने एप्लिकेशन

मिन पूल के लिए पूलिंग सक्षम बनाता है: कनेक्शन की न्यूनतम संख्या भी खुला रखने के लिए जब सभी सत्रों बंद हो जाती हैं।

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

कनेक्शन टाइमआउट: अधिकतम समय (सेकेंड में) पूल से एक नि: शुल्क कनेक्शन की प्रतीक्षा

कनेक्शन जीवनकाल: एक कनेक्शन पूल के लिए वापस आ जाता है, इसके निर्माण के समय वर्तमान समय के साथ तुलना की जाती है, और कनेक्शन नष्ट हो जाता है यदि उस समय अवधि (सेकेंड में) कनेक्शन लाइफटाइम द्वारा निर्दिष्ट मान से अधिक है। शून्य (0) का मान पूल कनेक्शन को अधिकतम कनेक्शन टाइमआउट करने का कारण बनता है।

इंक पूल आकार: सभी कनेक्शनों का उपयोग होने पर स्थापित कनेक्शन की संख्या नियंत्रित करता है।

डिकर पूल का आकार: कनेक्शन की संख्या को नियंत्रित करता है जब अत्यधिक स्थापित कनेक्शन का उपयोग नहीं किया जाता है।

http://www.codeproject.com/Articles/17768/ADO-NET-Connection-Pooling-at-a-Glance

संबंधित मुद्दे