NHibernate는 ADO.NET 데이터베이스 연결을 풀링하지 않는다. 연결은 트랜잭션이 커밋되거나 롤백 될 때만 닫힙니다. 소스 코드를 살펴보면 NHibernate가 ISession이 폐기 될 때 연결을 닫을 수 있도록 NHibernate를 구성 할 방법이 없다는 것을 알 수 있습니다.NHibernate와 ADO.NET 연결 풀링
이 동작의 목적은 무엇입니까? 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'
}
}
}
우리가
SessionImpl.cs 트랜잭션 여전히 이후 NHibernate에-세션의 폐기는 아무것도 실시하지 않습니다 :
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);
}
}
}
는 지금까지 내가 아는 한, 데이터베이스는 트랜잭션을 사용하기 위해 같은 연결이 필요합니다. 따라서 트랜잭션이 실행되는 동안 연결을 유지한다는 것이 이상하지 않은가? 연결이 풀로 반환되면 두 번째 풀에서 동일한 연결을받을 수 있도록하는 것이 없습니다. – jishi
그러나 구체적인 테스트에서는 ADO.NET의 일부인 기본 IdbConnection을 검사하고 있으며이 경우 테스트중인 ADO.NET 연결 풀링이 아닌지 확인합니다. 당신이해야 할 일은 똑같은 팩토리에서 두 개의 다른 세션을 만들고 똑같은 연결을 받는지 확인하는 것입니다. – jishi
각 트랜잭션의 시작 부분에서 Driver 클래스 (내 경우 OdbcDriver)가 새 DbConnection (OdbcConnection)을 만듭니다. 이 연결은 불필요한 전체 트랜잭션을 그대로 유지합니다. 필자가 작성한 테스트는 실제로 하나의 SessionFactory에서 두 개의 다른 세션을 사용합니다. – Antineutrino