C# 为什么不是';SQLT连接是否已处理/关闭?

C# 为什么不是';SQLT连接是否已处理/关闭?,c#,asp.net,static,idisposable,sqlconnection,C#,Asp.net,Static,Idisposable,Sqlconnection,给定方法: internal static DataSet SelectDataSet(String commandText, DataBaseEnum dataBase) { var dataset = new DataSet(); SqlConnection sqlc = dataBase == DataBaseEnum.ZipCodeDb ? new SqlConnection(ConfigurationManag

给定方法:

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)没有被释放/关闭

编辑1: 即使将其包装为using,我仍然可以看到连接正在使用(我已关闭连接池):

编辑2: 我从这里得到了一些帮助,可以进行更多的调试-答案是有人用池硬编码了一个连接字符串。感谢所有的帮助-如果可以的话,我会将所有的响应标记为答案。

C#的垃圾收集是不确定的,但该语言确实为如下资源处理提供了确定性结构:

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

这将创建一个
try/finally
块,该块将确保不管方法中发生了什么,都会释放连接对象。您确实应该将实现
IDisposable
的任何类型的实例包装在这样一个using块中,因为它将确保负责任地管理资源(如数据库连接等非托管资源),并为您提供所需的确定性控制。

在垃圾收集完成其工作后,它将是。打开文件流进行写入而不关闭文件流也是如此。即使代码超出范围,它也可能被“锁定”。

因为c#是一种垃圾收集语言,垃圾收集是不确定的。事实上,您的sqlconnection已被释放。你只是不能选择什么时候

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;
}

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;
    }
}

虽然在这种情况下,你可能会侥幸逃脱,因为

如果IDbConnection在调用Fill之前关闭,则会打开它以检索数据,然后关闭


因此,这意味着,如果您从一个封闭的连接开始,数据适配器应该为您处理它。我更关心的是,您将sql命令作为普通字符串传递。查询中必须不时有用户参数,这意味着您要将这些数据直接连接到命令字符串中不要那样做改为使用SqlCommand的Parameters集合。

我相信这与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"]))
    using (SqlCommand sqlcmd = sqlc.CreateCommand())
    {
        sqlcmd.CommandText = commandText;
        var adapter = new SqlDataAdapter(sqlcmd.CommandText, sqlc);
        adapter.Fill(dataset);

    }
    return dataset;
}

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;
    }
}


我同意这里的所有答案,再加上一种联系可能比一种方法的范围更广。当您需要在不同的地方使用现有连接时,情况会发生一些变化。始终确保在使用完所有实现了
IDisposable
的对象后,为它们调用
Dispose
。这是一个很好的实践,这样您就不会得到垃圾收集器无法决定如何处理的未使用对象