NHibernate 和 ADO.NET 連接池
似乎 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 也將不起作用,因為呼叫 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 連接並將連接返回到池(除非您提供了連接)。