NHibernate和ADO.NET连接池

Ant*_*ino 9 .net nhibernate 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'
        }
     }
  }
Run Code Online (Sandbox Code Playgroud)

处理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);
        }
    }
Run Code Online (Sandbox Code Playgroud)

注入自定义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);
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

Ste*_*ger 9

NHibernate有两种"模式".

  • 您可以在应用程序中打开连接,然后由应用程序来管理它.传递连接时使用此"模式" sessionfactory.OpenSession(connection).
  • 或者连接由NH创建.然后在会话结束时关闭它.未通过连接时使用此"模式"sessionfactory.OpenSession()

有一些支持TransactionScope.它最有可能使用第一个"模式".可能连接不是由NH持有,而是由交易范围.我不确切知道,我不使用环境事务.

NH 正在使用ADO.NET连接池.

您还可以使用ISession.Disconnect()和重新连接断开会话ISession.Reconnect().

文档中,您会发现:

方法ISession.Disconnect()将断开会话与ADO.NET连接的连接,并将连接返回到池(除非您提供了连接).