【问题标题】:Disposing SqlConnection when exception is thrown抛出异常时处理 SqlConnection
【发布时间】:2013-08-05 20:22:17
【问题描述】:

我想知道下面的代码模式:

    static SqlConnection getcon()
    {
        SqlConnection con = new SqlConnection("data source=foobar..");
        con.Open();

        // is con Disposed automatically or will it leak and live 
        // forever when exception is thrown?

        throw new Exception("exception");
        return con;
    }

    static void Main(string[] args)
    {
        try 
        {
            using (var scope = new TransactionScope())
            using (var con = getcon())
            using (var cmd = new SqlCommand("UPDATE SomeTable SET Column1 = 'test'", con))
            {                   
                cmd.ExecuteNonQuery();

                scope.Complete();
            }
        }
        catch     
        {
        }
    }

这是使用SqlConnection 的安全方法吗(从getcon() 方法获取连接)?当抛出异常时,它会在函数退出后被释放还是会永远存在?

我想要这个GetCon() 方法的目的是缩短代码并将连接创建和打开包装在一行中(using (var con = getcon())..)

【问题讨论】:

  • 我已经编辑了你的标题。请参阅“Should questions include “tags” in their titles?”,其中的共识是“不,他们不应该”。
  • 好的!但是,即使在“使用”行中发生异常,而不是在大括号 { } 内,连接是否也会被处理?
  • 为了避免输入 一行 代码 (conn.Open()) 来解决所有这些麻烦(并可能导致副作用和错误)似乎是非常错误的和过早的优化 - 不要这样做。这不值得。

标签: c# sqlconnection


【解决方案1】:
is con Disposed automatically or will it leak and live orever when exception is thrown?

throw new Exception("exception");
return con;//your code

实际上return con; 线是无法到达的。换句话说,它永远不会在这里执行。你没有返回con 方法实际上是通过抛出Exception 退出的。所以你的连接不会被清理here

当方法退出(异常)时,局部变量不在Scope 范围内,并且您没有对其的托管引用,因此显然您的conGarbage Collection 的约束。

will it leak and live orever when exception is thrown?

答案是否定的,垃圾收集器将负责回收Connection 使用的内存,并且当通常从Finalizer 调用Dispose(true) 时,您的连接将关闭。

编辑

假设你的 get con 方法没有抛出任何异常并返回一个 Connection 并且 Exception 被抛出如下

using (var scope = new TransactionScope())
using (var con = getcon())
using (var cmd = new SqlCommand("UPDATE SomeTable SET Column1 = 'test'", con))
{
    throw new Exception("Oops");//Throw excception somewhere here             
    cmd.ExecuteNonQuery();
    scope.Complete();
}

上述代码将保证在抛出异常时进行清理,因为您将 con 包装在 using 语句中。

希望对你有帮助

【讨论】:

    【解决方案2】:

    您编写 getcon 方法的方式(我假设您是专门为测试某些东西而编写的),con 将在抛出异常的那一刻被释放。由于'return con;'在您抛出异常之后,它永远不会返回给调用代码,并且会在 getcon 退出后立即被释放(超出范围)。

    【讨论】:

      【解决方案3】:

      我认为 jaadooviewer 的回答是正确的,但您似乎可以通过在 getcon 方法中使用 try/catch 块来完全避免这个问题。

      try
      {
          SQLConnection con = new SQLConnection("...");
          con.Open();
          if (/*condition*/)
              throw new Exception("Exception Condition Satisfied");
      }
      catch (Exception ex)
      {
          con.Dispose();
          throw ex;
      }
      return con;
      

      【讨论】:

      • 这里的主要问题是 Using -block 是否在 getcon() 方法中扩展了它的触角
      • @Jaska - 是的。 getcon() 在你的 using 块内被调用,所以它在块“内”,可以这么说。
      • 您可能希望将catch (Execption)throw; 结合使用,这样您就不会丢失堆栈跟踪。 (也 Dispose() 隐式调用 Close() 以获得 SqlConnection 所以你不需要在 catch 块中调用它)
      • 我不确定您的第一条评论是什么意思。感谢您对第二次的澄清。
      猜你喜欢
      • 1970-01-01
      • 2013-07-24
      • 1970-01-01
      • 2011-10-10
      • 2011-11-23
      • 1970-01-01
      • 1970-01-01
      • 2014-07-22
      • 1970-01-01
      相关资源
      最近更新 更多