2009-10-12 97 views
5

给出的方法:为什么不处理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: 有一些更多的调试与我从这里得到的帮助 - 答案是这个人硬编码连接字符串与池。感谢所有的帮助 - 如果可以的话,我会将所有回复标记为答案。

回答

19

C#的垃圾回收具有不确定性,但语言确实提供了资源配置这样的确定性结构:

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

这将创建一个try/finally块,这将确保连接对象配置不管是什么发生在该方法中。你真的应该把实现IDisposable的任何类型的实例包装在这样的使用块中,因为它可以确保负责任的资源管理(像数据库连接这样的非托管资源),并且它可以为你提供确定性的控制。

+0

+1整齐的答案,比我的好。 – 2009-10-12 03:41:26

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:

如果的IDbConnection被填充之前关闭被调用时,它被打开以检索数据和然后关闭。

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

1

我相信它与SqlConnection池有关。你可以做什么,而且我们经常在工作中将整个调用包装在使用语句中,这导致它调用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; 
    } 
} 

1

我同意这里的所有答案,加上一个连接可能是一个更广泛的范围,而不仅仅是一个方法。当你需要在不同的地方使用现有的连接时,场景会发生一些变化。对于实施IDisposable的所有对象,请务必在完成使用后确保致电Dispose。这是一个很好的做法,所以你最终不会得到垃圾收集器无法决定如何处理它们的未使用的对象。

相关问题