【问题标题】:Does using (var connection = new SqlConnection("ConnectionString")) still close/dispose the connection on error?是否使用 (var connection = new SqlConnection("ConnectionString")) 仍然关闭/处理错误连接?
【发布时间】:2011-09-26 08:12:49
【问题描述】:

我有以下代码

try
{
    using (var connection = new SqlConnection(Utils.ConnectionString))
    {
        connection.Open();

        using (var cmd = new SqlCommand("StoredProcedure", connection))
        {                            
            cmd.CommandType = System.Data.CommandType.StoredProcedure;
            var sqlParam = new SqlParameter("id_document", idDocument);
            cmd.Parameters.Add(sqlParam);

            int result = cmd.ExecuteNonQuery();
            if (result != -1)
                return "something";

            //do something here

            return "something else";
        }
    }

    //do something
}
catch (SqlException ex)
{
    return "something AKA didn't work";
}

问题是:如果using 括号({ })之间发生意外错误,var connection 是否仍会关闭?

问题是我对存储过程的大部分调用都是这样进行的,最近我收到了这个错误:

System.InvalidOperationException:超时已过期。超时 从池中获取连接之前经过的时间。这 可能已经发生,因为所有池连接都在使用中并且最大 已达到池大小。

我访问数据库的另一种方式是通过 nHibernate。

【问题讨论】:

    标签: c# .net sql-server tsql sqlconnection


    【解决方案1】:

    using Statement (C# Reference)

    using 语句确保 Dispose 被调用,即使 当您在对象上调用方法时发生异常。你可以 通过将对象放在 try 块中来实现相同的结果,然后 然后在 finally 块中调用 Dispose;事实上,这就是 using 语句由编译器翻译。代码示例 早期在编译时扩展为以下代码(注意额外的 花括号为对象创建有限的范围):

    【讨论】:

      【解决方案2】:

      是的,如果它进入using 语句的主体,它将在最后被释放......无论您是正常到达块的末尾,还是通过return 语句退出,还是抛出了异常。基本上using 语句等同于try/finally 块。

      这是唯一您获得连接的地方吗?就客户端代码而言,您的存储过程是否可能在某处死锁,从而使大量连接真正“忙碌”?

      【讨论】:

      • 如果池化的连接是打开的,在处理掉的时候会关闭吗?
      • @Tim:是的。请注意,这并不一定会关闭网络连接本身 - 它只是将其释放回连接池。
      • 是的,有可能出现死锁。但是,是的,这几乎就是我所有调用存储过程的工作方式。如果我不使用 using,我会使用 try、catch { throw } 和 finnaly。这样就只能进行调查了吗?
      • @Jon:感谢您的澄清。
      • 我相信您看到的问题是连接仅在垃圾收集运行时关闭/返回到池,因此在负载下您将用完连接。因此,异常表示在从池中获得连接之前已达到超时。您必须手动关闭连接 - 麻烦!
      【解决方案3】:

      就您的连接池用尽可用连接而言,如果您在分布式环境中并使用许多应用程序访问 SQL Server,但它们都使用相同的连接字符串,那么它们都将使用相同的池服务器。要解决此问题,您可以通过将连接 WorkstationID 设置为 Environment.MachineName 来更改每个应用程序的连接字符串。这将使服务器将每个连接视为不同,并为每台机器提供一个池,而不是共享池。

      在下面的示例中,我们甚至传入了一个令牌,以允许同一台机器上的应用程序拥有多个池。

      例子:

          private string GetConnectionStringWithWorkStationId(string connectionString, string connectionPoolToken)
          {
              if (string.IsNullOrEmpty(machineName)) machineName = Environment.MachineName;
      
              SqlConnectionStringBuilder cnbdlr;
              try
              {
                  cnbdlr = new SqlConnectionStringBuilder(connectionString);
              }
              catch
              {
                  throw new ArgumentException("connection string was an invalid format");
              }
      
              cnbdlr.WorkstationID = machineName + connectionPoolToken;
      
              return cnbdlr.ConnectionString;
          }
      

      【讨论】:

        【解决方案4】:

        用这个替换你上面的代码..并再次检查..

        try
        {
            using (var connection = new SqlConnection(Utils.ConnectionString))
            {
                connection.Open();
                using (var cmd = new SqlCommand("StoredProcedure", connection))
                {                            
                    cmd.CommandType = System.Data.CommandType.StoredProcedure;
                    var sqlParam = new SqlParameter("id_document", idDocument);
                    cmd.Parameters.Add(sqlParam);
        
                    int result = cmd.ExecuteNonQuery();
                    if (result != -1)
                        return "something";
        
                    //do something here
        
                    return "something else";
        
                }
        
                connection.Close();
                connection.Dispose();
            }
        
            //do something
        
        }
        catch (SqlException ex)
        {
            return "something AKA didn't work";
        }
        

        【讨论】:

          【解决方案5】:

          这是一个参考:

          http://msdn.microsoft.com/en-us/library/yh598w02(v=vs.80).aspx

          我知道的是,如果你在 using {} 子句中使用一个对象,那么该对象会继承 IDisposable 接口(即 SqlConnection 继承 DbConnection,而 DbConnection 继承 IDisposable),这意味着如果你遇到异常,任何对象都会被关闭并妥善处理。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-06-28
            • 2010-11-14
            • 2014-09-14
            • 2012-02-20
            • 2016-05-21
            • 1970-01-01
            相关资源
            最近更新 更多