我需要明确关闭和显式释放SQLConnection吗?

3
SqlDataReader rdr = null;
con = new SqlConnection(objUtilityDAL.ConnectionString);
using (SqlCommand cmd = con.CreateCommand())
{
    try
    {
        if (con.State != ConnectionState.Open)
            con.Open();
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.Add(Parameter);
        cmd.CommandText = _query;
        rdr = cmd.ExecuteReader();
    }
    catch (Exception ex)
    {
        throw ex;
    }
}

在上述代码中,sqlconnection在托管代码内部被打开。因此,在使用范围结束时,连接对象会自动被处理吗?

您的连接对象不在 using 语句的范围内。 - Steve
3个回答

7

由于SqlConnection是一个可释放对象,因此您需要关心它的处理。您可以尝试以下操作:

using(var sqlConnection = new SqlConnection(objUtilityDAL.ConnectionString))
{
    using (SqlCommand cmd = con.CreateCommand())
    {
        // the rest of your code - just replace con with sqlConnection
    }
}

我建议你用一个本地变量来替换con - 如果还没有的话(从您发布的代码中并不明显)。没有必要为此使用类字段。只需创建一个本地变量,跟踪它会更清晰。


1
看起来 con 可能是一个字段。我不建议在 using 语句中使用字段。因为一旦在该方法中将其释放,您尝试在其他地方使用该字段时将会发生异常,因为对象已被释放。使用局部变量不是更好的选择避免上述情况吗?此外,与局部变量相比,被释放的字段甚至没有任何优势。或者我错了吗? - L. Guthardt
通过快速阅读帖子,我没有注意到这可能是一个类字段 :). 说得好!正如我在更新中所写的那样,我认为利用类字段并不是一个好主意。 - Christos
谢谢。 :) 很好,你更新了答案并添加了这些信息。+1 - L. Guthardt
非常感谢你,Christos。你建议我使用局部变量而不是类变量的观点很有道理,因为它会在方法内部被处理掉。我会改变逻辑。再次感谢! - Chinchan

2

你应该手动释放每个临时的IDisposable实例,即将它们包装到using中:

   // Connecton is IDisposable; we create it 
   //   1. manually - new ...
   //   2. for temporary usage (just for the query)
   using (SqlConnection con = new SqlConnection(objUtilityDAL.ConnectionString)) {
     // Check is redundant here: new instance will be closed 
     con.Open();

     // Command is IDisposable
     using (SqlCommand cmd = con.CreateCommand()) {
       cmd.CommandType = CommandType.StoredProcedure;
       cmd.Parameters.Add(Parameter);
       cmd.CommandText = _query;

       // Finally, Reader - yes - is IDisposable 
       using (SqlDataReader rdr = cmd.ExecuteReader()) {
         // while (rdr.Read()) {...}
       }
     }   
   }

请注意,
   try {
     ...
   }
   catch (Exception ex) {
     throw ex;
  } 

至少是冗余的(它什么也不做,只是重新抛出异常,同时丢失堆栈跟踪),因此可以被删除


非常感谢 Dmitry Bychenko。 - Chinchan
2
不要将异常重新抛出,否则会丢失堆栈跟踪信息... 只使用 throw; - Yousha Aleayoub

2
一般来说:
在 .Net 框架中,没有任何东西会自动清除。否则我们就不需要 IDisposable 接口了。垃圾回收器只能处理托管资源,因此每个非托管资源必须在 dispose 方法中通过代码处理。
所以通常情况下,实现 IDisposable 接口的每个类的每个实例必须通过显式调用其 Dispose 方法或使用 using 语句隐式处理。
作为最佳实践,您应该努力将实现 IDisposable 接口的任何内容用作 using 语句中的局部变量:
using(var whatever = new SomeIDisposableImplementation())
{
    // use the whatever variable here
}

“using”语句是一种语法糖。编译器将其转换为类似于以下内容的代码:
var whatever = new SomeIDisposableImplementation();
try
{
    // use the whatever variable here
}
finally
{
    ((IDisposable)whatever).Dispose();
}

由于无论在try块中发生什么,finally块都有保证运行,因此可以保证您的IDisposable实例将被正确处理。
特别是对于SqlConnection为了将连接对象返回到连接池中,必须在完成后将其释放(Dispose方法也将关闭连接,因此不需要显式关闭)- 因此,SqlConnection的正确使用方式始终是作为using语句内的局部变量:
using(var con = new SqlConnection(connectionString))
{
    // do stuff with con here
}

非常感谢 @Zohar Peled - Chinchan
很高兴能帮助 :-) - Zohar Peled

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接