NHibernate和ADO.NET连接池 [英] NHibernate and ADO.NET Connection Pooling

查看:101
本文介绍了NHibernate和ADO.NET连接池的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

似乎NHibernate不合并ADO.NET数据库连接.仅在提交或回滚事务时关闭连接.对源代码的回顾表明,没有方法可以配置NHibernate,以便在处置ISession时关闭NHibernate.

It seems that NHibernate does not pool ADO.NET database connections. Connections are only closed when the transaction is committed or rolled back. A review of the source code shows that there is no way to configure NHibernate so that it is closing connections when the ISession is disposed.

此行为的目的是什么? ADO.NET本身具有连接池.无需在交易中一直将它们保持打开状态.通过这种行为,也不必要地创建了分布式事务. http://中描述的可能的解决方法davybrion.com/blog/2010/05/avoiding-leaking-connections-with-nhibernate-and-transactionscope/因此不起作用(至少不适用于NHibernate 3.1.0).我正在使用Informix.其他所有数据库似乎都存在相同的问题( NHibernate连接池).

What was the intent of this behaviour? ADO.NET has connection pooling itself. There's no need to hold them open all the time within the transaction. With this behaviour are also unneccessaryly distributed transactions created. A possible workaround described in http://davybrion.com/blog/2010/05/avoiding-leaking-connections-with-nhibernate-and-transactionscope/ therefore does not work (at least not with NHibernate 3.1.0). I am using Informix. The same problem seems to exisit for every other database (NHibernate Connection Pooling).

还有其他解决方法或建议可以避免此问题?

Is there any other workaround or advice avoiding this problem?

这是重现问题的单元测试:

Here's a unit test reproducing the problem:

  [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的处理无济于事,因为我们仍在交易中

The disposing of the NHibernate-Session does nothing since we are still in a transaction

SessionImpl.cs:

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也不起作用,因为调用ConnectionProvider的ConnectionManager具有几个前提条件,即检查不允许在事务中关闭连接.

Injecting a custom ConnectionProvider will also not work since the ConnectionManager calling the ConnectionProvider has several preconditions checking that closing a connection within a transaction is not allowed.

ConnectionManager.cs:

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具有两个模式".

NHibernate has two "modes".

  • 您可以在应用程序中打开连接,然后由应用程序来管理它.将连接传递到sessionfactory.OpenSession(connection)时使用此模式".
  • 或者连接是由NH创建的.然后,当会话关闭时,它关闭.不将连接传递到sessionfactory.OpenSession()
  • 时使用此模式"
  • Either you open the connection in your application, then it is up to the application to manage it. This "mode" is used when passing a connection to sessionfactory.OpenSession(connection).
  • Or the connection is created by NH. Then it is closed when the session is closed. This "mode" is used when not passing a connection to sessionfactory.OpenSession()

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

There is some support for TransactionScope. It is most probably using the first "mode". Probably the connection is not hold by NH, but by the transaction scope. I don't know exactly, I don't use environment transactions.

NH 使用ADO.NET连接池.

NH is using the ADO.NET connection pool by the way.

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

You can also disconnect the session using ISession.Disconnect() and reconnect using ISession.Reconnect().

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

The method ISession.Disconnect() will disconnect the session from the ADO.NET connection and return the connection to the pool (unless you provided the connection).

这篇关于NHibernate和ADO.NET连接池的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆