2009-07-23 39 views
4

靜態類中的以下方法會導致超時異常,因爲連接池已最大化。C#中的連接泄漏DataBase.ExecuteScalar

在調試模式下,我查看了SQL Management Studio,看到有150個睡眠進程。

我預計連接會自動關閉......我也嘗試把它作爲一個靜態成員,並仍然得到相同的錯誤。

任何想法? 繼承人的代碼:

public static Decimal ExecuteScalarDec(string procName, params object[] parameters) 
{ 
    try 
    { 
     return (Decimal)DatabaseFactory.CreateDatabase().ExecuteScalar(procName, parameters); 
    } 
    catch (Exception ex) 
    { 
     throw new Exception(procName.ToString() + " " + parameters.ToString(), ex); 
    } 
} 

「根據設計,大多數的數據庫類方法處理連接的打開和關閉每次調用數據庫因此,應用程序代碼並不需要包括管理連接的代碼「。 ExecuteReader是一個異常(因爲它返回一個資源)。 ExecuteScalar處於陷阱狀態:它返回一個'標量'。但是,我猜標量可能很重,例如。從大數據類型返回構建的Stream,並且需要保持打開狀態。 - 萊姆斯Rusanu

,因爲它說:「評論要求50的聲譽」我註冊了我的用戶後,我不能對你的解答發表評論......

我在返回一個的ExecuteScalar列ID()和該值返回 - 我知道這是因爲執行標量的下一個調用只有在我收到一個值後纔會調用... 它沒有縫意義,流將永遠保持打開狀態 而我在sql管理中看到所有的進程都在睡覺。

+0

ExecuteScalar()方法是如何處理底層DbConnection對象的 - 它調用Dispose()或Close()方法,例如通過使用一個「使用」聲明? – 2009-07-23 06:29:03

回答

5
public static Decimal ExecuteScalarDec(string procName, params object[] parameters) 
{ 
    try 
    { 
     using (Database database = DatabaseFactory.CreateDatabase()) 
     { 
      return (Decimal)database.ExecuteScalar(procName, parameters); 
     } 
    } 
    catch (Exception ex) 
    { 
     throw new Exception(procName.ToString() + " " + parameters.ToString(), ex); 
    } 
} 

更新

OK,因爲這是EnterpriseLibrary代碼。該Database類實現ExecuetScalar這樣的(其他簽名會崩潰到這最終):

public virtual object ExecuteScalar(DbCommand command) 
     { 
      if (command == null) throw new ArgumentNullException("command"); 

      using (ConnectionWrapper wrapper = GetOpenConnection()) 
      { 
       PrepareCommand(command, wrapper.Connection); 
       return DoExecuteScalar(command); 
      } 
     } 

和ConnectionWrapper部署的連接(在鏈接源文件的結束),因此,從理論上說,您的通話應該是確定並處理連接。

的GetOpenConnection()方法返回一個包裝,不處置的連接...除非一個當前TransactionScopeConnections存在:

protected ConnectionWrapper GetOpenConnection(bool disposeInnerConnection) 
    { 
     DbConnection connection = TransactionScopeConnections.GetConnection(this); 
     if (connection != null) 
     { 
      return new ConnectionWrapper(connection, false); 
     } 

     return new ConnectionWrapper(GetNewOpenConnection(), disposeInnerConnection); 
    } 

這裏是如何TransactionScopeConnections返回連接:

public static DbConnection GetConnection(Database db) 
    { 
     Transaction currentTransaction = Transaction.Current; 

     if (currentTransaction == null) 
      return null; 

     Dictionary<string, DbConnection> connectionList; 
     DbConnection connection; 

     lock (transactionConnections) 
     { 
      if (!transactionConnections.TryGetValue(currentTransaction, out connectionList)) 
      { 
       // We don't have a list for this transaction, so create a new one 
       connectionList = new Dictionary<string, DbConnection>(); 
       transactionConnections.Add(currentTransaction, connectionList); 

       // We need to know when this previously unknown transaction is completed too 
       currentTransaction.TransactionCompleted += OnTransactionCompleted; 
      } 
     } 

     lock (connectionList) 
     { 
      // Next we'll see if there is already a connection. If not, we'll create a new connection and add it 
      // to the transaction's list of connections. 
      // This collection should only be modified by the thread where the transaction scope was created 
      // while the transaction scope is active. 
      // However there's no documentation to confirm this, so we err on the safe side and lock. 
      if (!connectionList.TryGetValue(db.ConnectionString, out connection)) 
      { 
       // we're betting the cost of acquiring a new finer-grained lock is less than 
       // that of opening a new connection, and besides this allows threads to work in parallel 
       connection = db.GetNewOpenConnection(); 
       connectionList.Add(db.ConnectionString, connection); 
      } 
     } 

     return connection; 
    } 

現在,除非我錯了,否則TransactionsScopeConnections將始終爲全新的數據庫對象(如您的情況)創建一個新的連接並將它們保存在內部字典中。數據庫對象沒有實現一次性,所以我迷失在確定誰應該清理這個TransactionScopeConnecitons內部列表中的連接。

Matt,是否可以按照this article about CLR leaks中的步驟操作並查看過程中是否有大量數據庫對象?加載SOS並執行!dumpheap -type Microsoft.Practices.EnterpriseLibrary.Data.Database。如果你發現許多對象,你能跟蹤其中的一些針堆棧嗎?!gcroot <AddressOfObject>

+2

這不起作用,因爲數據庫不是一次性使用 – Matt 2009-07-23 06:34:29