在“使用”块中是SqlConnection在返回或异常时关闭?

时间:2011-01-17 20:55:34

标签: c# using sqlconnection

第一个问题:
说我有

using (SqlConnection connection = new SqlConnection(connectionString))
{
    connection.Open();

    string storedProc = "GetData";
    SqlCommand command = new SqlCommand(storedProc, connection);
    command.CommandType = CommandType.StoredProcedure;
    command.Parameters.Add(new SqlParameter("@EmployeeID", employeeID));

    return (byte[])command.ExecuteScalar();
}

连接是否已关闭?因为从技术上讲,我们永远不会像我们}之前那样到达return

第二个问题:
这次我有:

try
{
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
        int employeeID = findEmployeeID();

        connection.Open();
        SqlCommand command = new SqlCommand("UpdateEmployeeTable", connection);
        command.CommandType = CommandType.StoredProcedure;
        command.Parameters.Add(new SqlParameter("@EmployeeID", employeeID));
        command.CommandTimeout = 5;

        command.ExecuteNonQuery();
    }
}
catch (Exception) { /*Handle error*/ }

现在,在try的某个地方说我们收到错误并被抓住了。连接是否仍然关闭?因为我们再次跳过try中的其余代码并直接转到catch语句。

我是否对using的工作原理过于线性思考?即当我们离开Dispose()范围时,using是否会被调用?

7 个答案:

答案 0 :(得分:170)

  1. 无论哪种方式,当退出使用块时(通过成功完成或错误),它将被关闭。

    虽然我认为组织这样的 更好 ,因为要看到将要发生的事情要容易得多,即使对于将支持的新维护程序员也是如此它后来:

    using (SqlConnection connection = new SqlConnection(connectionString)) 
    {    
        int employeeID = findEmployeeID();    
        try    
        {
            connection.Open();
            SqlCommand command = new SqlCommand("UpdateEmployeeTable", connection);
            command.CommandType = CommandType.StoredProcedure;
            command.Parameters.Add(new SqlParameter("@EmployeeID", employeeID));
            command.CommandTimeout = 5;
    
            command.ExecuteNonQuery();    
        } 
        catch (Exception) 
        { 
            /*Handle error*/ 
        }
    }
    

答案 1 :(得分:43)

对这两个问题都是肯定的。 using语句被编译成try / finally块

using (SqlConnection connection = new SqlConnection(connectionString))
{
}

相同
SqlConnection connection = null;
try
{
    connection = new SqlConnection(connectionString);
}
finally
{
   if(connection != null)
        ((IDisposable)connection).Dispose();
}

编辑:将演员表修复为Disposable http://msdn.microsoft.com/en-us/library/yh598w02.aspx

答案 2 :(得分:14)

这是我的模板。从SQL服务器中选择数据所需的一切。关闭并处理连接,并捕获连接和执行中的错误。

string connString = System.Configuration.ConfigurationManager.ConnectionStrings["CompanyServer"].ConnectionString;
string selectStatement = @"
    SELECT TOP 1 Person
    FROM CorporateOffice
    WHERE HeadUpAss = 1 AND Title LIKE 'C-Level%'
    ORDER BY IntelligenceQuotient DESC
";
using (SqlConnection conn = new SqlConnection(connString))
{
    using (SqlCommand comm = new SqlCommand(selectStatement, conn))
    {
        try
        {
            conn.Open();
            using (SqlDataReader dr = comm.ExecuteReader())
            {
                if (dr.HasRows)
                {
                    while (dr.Read())
                    {
                        Console.WriteLine(dr["Person"].ToString());
                    }
                }
                else Console.WriteLine("No C-Level with Head Up Ass Found!? (Very Odd)");
            }
        }
        catch (Exception e) { Console.WriteLine("Error: " + e.Message); }
        if (conn.State == System.Data.ConnectionState.Open) conn.Close();
    }
}

*修订日期:2015-11-09 *
正如尼克的建议;如果太多的括号让你烦恼,请按照这样的格式......

using (SqlConnection conn = new SqlConnection(connString))
   using (SqlCommand comm = new SqlCommand(selectStatement, conn))
   {
      try
      {
         conn.Open();
         using (SqlDataReader dr = comm.ExecuteReader())
            if (dr.HasRows)
               while (dr.Read()) Console.WriteLine(dr["Person"].ToString());
            else Console.WriteLine("No C-Level with Head Up Ass Found!? (Very Odd)");
      }
      catch (Exception e) { Console.WriteLine("Error: " + e.Message); }
      if (conn.State == System.Data.ConnectionState.Open) conn.Close();
   }

然后,如果您为EA或DayBreak游戏工作,您也可以放弃任何换行符,因为这些只适用于那些必须回来查看您的代码并且真正关心的人?我对吗?我的意思是1行而不是23行意味着我是一个更好的程序员,对吧?

using (SqlConnection conn = new SqlConnection(connString)) using (SqlCommand comm = new SqlCommand(selectStatement, conn)) { try { conn.Open(); using (SqlDataReader dr = comm.ExecuteReader()) if (dr.HasRows) while (dr.Read()) Console.WriteLine(dr["Person"].ToString()); else Console.WriteLine("No C-Level with Head Up Ass Found!? (Very Odd)"); } catch (Exception e) { Console.WriteLine("Error: " + e.Message); } if (conn.State == System.Data.ConnectionState.Open) conn.Close(); }
先生......好的。我从我的系统中得到了这个,并且我已经做了一段时间。继续。

答案 3 :(得分:5)

当您离开使用范围时,只会调用Dispose。 "使用"的意图是为开发人员提供有保证的方法,以确保资源得到处置。

来自MSDN

  

当达到using语句的结尾或者抛出异常并且控制在语句结束之前离开语句块时,可以退出using语句。

答案 4 :(得分:4)

Using围绕正在分配的对象生成try / finally,并为您调用Dispose()

它可以省去手动创建try / finally块并调用Dispose()

的麻烦

答案 5 :(得分:2)

在第一个示例中,C#编译器实际上将using语句转换为以下内容:

SqlConnection connection = new SqlConnection(connectionString));

try
{
    connection.Open();

    string storedProc = "GetData";
    SqlCommand command = new SqlCommand(storedProc, connection);
    command.CommandType = CommandType.StoredProcedure;
    command.Parameters.Add(new SqlParameter("@EmployeeID", employeeID));

    return (byte[])command.ExecuteScalar();
}
finally
{
    connection.Dispose();
}

最后语句将始终在函数返回之前被调用,因此连接将始终关闭/处置。

因此,在您的第二个示例中,代码将编译为以下内容:

try
{
    try
    {
        connection.Open();

        string storedProc = "GetData";
        SqlCommand command = new SqlCommand(storedProc, connection);
        command.CommandType = CommandType.StoredProcedure;
        command.Parameters.Add(new SqlParameter("@EmployeeID", employeeID));

        return (byte[])command.ExecuteScalar();
    }
    finally
    {
        connection.Dispose();
    }
}
catch (Exception)
{
}

将在finally语句中捕获异常并关闭连接。外部catch子句不会看到异常。

答案 6 :(得分:1)

我在 try / catch 块中编写了两个使用语句,我可以看到如果它被放置,异常被捕获了在内部使用语句中,就像ShaneLS example

     try
     {
       using (var con = new SqlConnection(@"Data Source=..."))
       {
         var cad = "INSERT INTO table VALUES (@r1,@r2,@r3)";

         using (var insertCommand = new SqlCommand(cad, con))
         {
           insertCommand.Parameters.AddWithValue("@r1", atxt);
           insertCommand.Parameters.AddWithValue("@r2", btxt);
           insertCommand.Parameters.AddWithValue("@r3", ctxt);
           con.Open();
           insertCommand.ExecuteNonQuery();
         }
       }
     }
     catch (Exception ex)
     {
       MessageBox.Show("Error: " + ex.Message, "UsingTest", MessageBoxButtons.OK, MessageBoxIcon.Error);
     }

无论放置 try / catch 的位置,都会毫无问题地捕获异常。