2009-07-23 8 views
4

静的クラスの次のメソッドは、接続プールが最大になっているためタイムアウト例外が発生します。C#での接続リークDataBase.ExecuteScalar

デバッグモードでは、私はSQL Management Studioを見て、150のスリーププロセスがあることを確認しました。

私は接続が自動的に閉じられると予想しました...私も静的なメンバーとして入れてみましたが、まだ同じエラーがあります。

すべてのアイデア? はHERESにコード:、Databaseクラスのメソッドのほとんどは、各コール上のデータベースへの接続の開閉を

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はlimboにあります: 'スカラー'を返します。しかし、私はスカラーがかなり重いことができると思います。大規模なデータ型のリターンから構築されたStreamで、Conenctionを開いたままにする必要があります。 - レムスRusanu

それは私が私のユーザーを登録した後、「コメントは50の評判が必要です」と言うので、私はあなたの答えにはコメントできない

...私は)は、ExecuteScalarの列同上(返すよ

と値が返されます - スカラーを実行する次の呼び出しが値を受け取った後に呼び出されるだけなので、私はこれを知っています... ストリームが永遠に開いたままになることを意味する縫い目はありませんそしてSQL管理で見たすべてのプロセスが眠っています。

+0

ExecuteScalar()メソッドは、基になるDbConnectionオブジェクトと何をするのですか?Dispose()またはClose()を呼び出しますか? "using"ステートメント? –

答えて

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接続(リンク内のソースファイルの末尾に)配置ので、理論が行く、あなたのコールする必要がありますOKをクリックして接続を破棄します。

GetOpenConnection()メソッドは、1が現在の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は(あなたの場合のように)常に新しいデータベースオブジェクトの新鮮な賛辞を作成し、内部の辞書に保持します。データベースオブジェクトはDisposableを実装していないので、このTransactionScopeConnecitons内部リストから接続をクリーンアップすることになっている人を正確に特定することはできません。

マットは、this article about CLR leaksの手順を実行して、プロセスに多数のデータベースオブジェクトがあるかどうかを確認することは可能ですか?SOSをロードし、!dumpheap -type Microsoft.Practices.EnterpriseLibrary.Data.Databaseを実行してください。多くのオブジェクトが見つかった場合は、一部のピンスタックをトレースできますか?!gcroot <AddressOfObject>

+2

データベースが使い捨てではないため、これは機能しません – Matt

+1

使い捨てにするか、今から翌日までのリーク接続を追跡してください。 –

+0

それはあなたのデータベースクラスの欠点です:使い捨てではないなら、ExecuteScalarメソッドで* it *がコネクションを廃棄することを確認する必要があります。 –

関連する問題