簡體   English   中英

NHibernate和ADO.NET連接池

[英]NHibernate and ADO.NET Connection Pooling

似乎NHibernate不會集合ADO.NET數據庫連接。 僅在提交或回滾事務時關閉連接。 對源代碼的回顧表明,沒有辦法配置NHibernate,以便在處理ISession時關閉連接。

這種行為的意圖是什么? ADO.NET本身就有連接池。 在交易中不需要一直打開它們。 使用此行為也是不必要的分布式事務創建。 因此, http: //davybrion.com/blog/2010/05/avoiding-leaking-connections-with-nhibernate-and-transactionscope/中描述的可能解決方法不起作用(至少不適用於NHibernate 3.1.0)。 我正在使用Informix。 對於每個其他數據庫( NHibernate Connection Pooling ),似乎存在同樣的問題。

有沒有其他解決方法或建議避免這個問題?

這是一個重現問題的單元測試:

  [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-Session沒有任何作用,因為我們仍處於事務中

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);
        }
    }

注入自定義ConnectionProvider也不起作用,因為ConnectionManager調用ConnectionProvider有幾個先決條件,檢查不允許在事務中關閉連接。

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);
            }
        }
    }

NHibernate有兩種“模式”。

  • 您可以在應用程序中打開連接,然后由應用程序來管理它。 將連接傳遞給sessionfactory.OpenSession(connection)時使用此“模式”。
  • 或者連接由NH創建。 然后在會話結束時關閉它。 未傳遞連接到sessionfactory.OpenSession()時使用此“模式”

TransactionScope有一些支持。 它最有可能使用第一個“模式”。 可能連接不是由NH持有,而是由交易范圍。 我不確切知道,我不使用環境事務。

NH 正在使用ADO.NET連接池。

您也可以斷開使用會話ISession.Disconnect()並使用重新ISession.Reconnect()

文檔中,您會發現:

方法ISession.Disconnect()將斷開會話與ADO.NET連接的連接,並將連接返回到池(除非您提供了連接)。

您可以通過將以下設置添加到連接字符串來完成此操作。

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

池:為您的應用程序啟用池

最小池:即使所有會話都關閉也要保持打開的最小連接數。

最大池數:應用程序將向數據庫打開的最大連接數。 達到最大值時,它將等待“連接超時”指定的秒數,然后拋出異常。

連接超時:等待池中的空閑連接的最長時間(以秒為單位)

連接生存期:將連接返回到池時,將其創建時間與當前時間進行比較,如果該時間跨度(以秒為單位)超過Connection Lifetime指定的值,則會破壞連接。 值為零(0)會導致池連接具有最大連接超時。

Incr Pool Size:控制使用所有連接時建立的連接數。

Decr池大小:控制在未使用過多已建立連接時關閉的連接數。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM