[英]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)
时使用此“模式”。 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.