鉴于方法:
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: 我从这里得到了一些更多的调试帮助 - 答案是有人硬编码连接字符串与池。感谢所有的帮助 - 如果可以的话,我会将所有回复标记为答案。
答案 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
。这是一个很好的做法,所以你不会得到垃圾收集器无法决定如何处理它们的未使用的对象。