6

メソッドを考えると:

internal static DataSet SelectDataSet(String commandText, DataBaseEnum dataBase)
{
    var dataset = new DataSet();

    SqlConnection sqlc = dataBase == DataBaseEnum.ZipCodeDb
                             ? new SqlConnection(ConfigurationManager.AppSettings["ZipcodeDB"])
                             : new SqlConnection(ConfigurationManager.AppSettings["WeatherDB"]);
    SqlCommand sqlcmd = sqlc.CreateCommand();
    sqlcmd.CommandText = commandText;
    var adapter = new SqlDataAdapter(sqlcmd.CommandText, sqlc);
    adapter.Fill(dataset);


    return dataset;
}

呼び出し元のメソッドがスコープ外になった後、または sqlc に参照がなくなった後、sqlc (SqlConnection) が破棄/クローズされないのはなぜですか?

EDIT 1: 使用してラップしても、使用して接続を確認できます(接続プールをオフにしています):

SELECT DB_NAME(dbid) as 'Database Name',
COUNT(dbid) as 'Total Connections'
FROM sys.sysprocesses WITH (nolock)
WHERE dbid > 0
GROUP BY dbid

EDIT 2: here から得た助けを借りて、さらにデバッグを行ってください-答えは、誰かがプールで接続文字列をハードコーディングしたことでした。助けてくれてありがとう - できれば、すべての回答を回答としてマークします。

4

5 に答える 5

20

C# のガベージ コレクションは非決定論的ですが、言語は次のようにリソースを破棄するための決定論的な構造を提供します。

using (SqlConnection connection = new SqlConnection(...))
{
    // ...  
}

try/finallyこれにより、メソッドで何が起こっても接続オブジェクトが破棄されることを保証するブロックが作成されます。このような using ブロックで実装する型のインスタンスはすべてラップする必要があります。IDisposableこれにより、責任を持ってリソース管理 (データベース接続などの管理されていないリソース) が保証され、探している決定論的な制御が得られるからです。

于 2009-10-12T03:36:56.600 に答える
3

c#はガベージコレクション言語であり、ガベージコレクションは決定論的ではないためです。それの事実はあなたのsqlconnection処分されるということです。いつ選択することはできません。

SQL接続は限られたリソースであり、不足するのに十分な数のSQL接続を作成する可能性があります。代わりに次のように記述してください。

internal static DataSet SelectDataSet(String commandText, DataBaseEnum dataBase)
{
    var dataset = new DataSet();

    using (SqlConnection sqlc = dataBase == DataBaseEnum.ZipCodeDb
                             ? new SqlConnection(ConfigurationManager.AppSettings["ZipcodeDB"])
                             : new SqlConnection(ConfigurationManager.AppSettings["WeatherDB"]))
    using (SqlCommand sqlcmd = sqlc.CreateCommand())
    {
        sqlcmd.CommandText = commandText;
        var adapter = new SqlDataAdapter(sqlcmd.CommandText, sqlc);
        adapter.Fill(dataset);

    }
    return dataset;
}

この場合、.Fill()メソッドは奇妙な獣であるため、それでうまくいくかもしれませんが:

Fillが呼び出される前にIDbConnectionが閉じられると、データを取得するためにIDbConnectionが開かれ、その後閉じられます。

つまり、接続を閉じた状態から始める場合は、データアダプタが自動的に処理する必要があります。sqlコマンドをプレーンな文字列として渡しているのではないかと心配しています。クエリには時々ユーザーパラメータが必要です。これは、そのデータをコマンド文字列に直接連結していることを意味します。 そんなことしないで! 代わりに、SqlCommandのParamtersコレクションを使用します。

于 2009-10-12T03:39:46.377 に答える
2

私はここでのすべての答えに同意します。さらに、接続は単なる方法よりも広い範囲である可能性があります。さまざまな場所で既存の接続を使用する必要がある場合、シナリオは少し変わります。使い終わったら、必ずDispose実装するすべてのオブジェクトを呼び出してください。IDisposableこれは良い習慣なので、ガベージコレクターがそれらをどう処理するかを決定できない未使用のオブジェクトになってしまうことはありません。

于 2009-10-12T04:01:44.443 に答える
1

SqlConnectionプーリングと関係があると思います。あなたができること、そして私たちが仕事でよく行うことは、呼び出し全体をusingステートメントでラップすることです。これにより、dispose()メソッドが呼び出され、接続が閉じられ、オブジェクトが破棄されます。

次に、代わりに次のようなことを行うことができます。


internal static DataSet SelectDataSet(String commandText, DataBaseEnum dataBase)
{
    var dataset = new DataSet();

    using(SqlConnection sqlc = dataBase == DataBaseEnum.ZipCodeDb
                             ? new SqlConnection(ConfigurationManager.AppSettings["ZipcodeDB"])
                             : new SqlConnection(ConfigurationManager.AppSettings["WeatherDB"])) {
        SqlCommand sqlcmd = sqlc.CreateCommand();
        sqlcmd.CommandText = commandText;
        var adapter = new SqlDataAdapter(sqlcmd.CommandText, sqlc);
        adapter.Fill(dataset);


        return dataset;
    }
}

于 2009-10-12T03:39:58.497 に答える
1

ガベージコレクションが仕事をした後になります。ファイルストリームを閉じずに書き込み用に開く場合も同様です。コードが範囲外になったとしても、「ロック」される可能性があります。

于 2009-10-12T03:37:04.230 に答える