为什么不处理/关闭SqlConnection?

时间:2009-10-12 03:34:37

标签: 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(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(SqlConnection)在调用方法超出范围后没有处理/关闭,或者sqlc没有更多引用?

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

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

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

5 个答案:

答案 0 :(得分:19)

C#的垃圾收集是非确定性的,但语言确实提供了一个确定性的资源处理结构,如下所示:

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

这将创建一个try/finally块,无论方法中发生什么,都将确保处置连接对象。您真的应该在这样的使用块中包装实现IDisposable的任何类型的实例,因为它将确保负责任的资源管理(非托管资源,如数据库连接),并且它还为您提供您正在寻找的确定性控制。

答案 1 :(得分:2)

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

虽然在这种情况下你可能会侥幸成功,因为.Fill() method is a strange beast:

  

如果在调用Fill之前关闭了IDbConnection,它将被打开以检索数据然后关闭。

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

答案 2 :(得分:1)

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

答案 3 :(得分:1)

我认为它与SqlConnection池有关。你可以做什么,我们经常在工作中将整个调用包装在一个using语句中,这使得它调用dispose()方法,hense关闭连接并处理对象

然后你可以做这样的事情:


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

答案 4 :(得分:1)

我同意这里的所有答案,而且连接可能比一个方法更广泛。当您需要在不同位置使用现有连接时,方案会有所改变。在使用完{1}后,务必确保为Dispose所有对象调用IDisposable。这是一个很好的做法,所以你不会得到垃圾收集器无法决定如何处理它们的未使用的对象。