【问题标题】:Using Block with Stored Procedures将块与存储过程一起使用
【发布时间】:2013-03-26 14:12:58
【问题描述】:

我正在尝试习惯在 C# 中使用“使用”块,但我很难理解何时应该使用它们。

这是一个例子。

我的原始代码,没有using 块:

SqlConnection conn = new SqlConnection(cCon.getConn());
    SqlCommand cmd = new SqlCommand("sp_SaveSomething", conn);
    cmd.CommandType = CommandType.StoredProcedure;
    cmd.Parameters.Add(new SqlParameter("@x", xxx));
    cmd.Parameters.Add(new SqlParameter("@ORG", ORG));        
    try
    {
        conn.Open();
        cmd.ExecuteNonQuery();
    }
    catch (Exception ex)
    { }
    finally
    {
        conn.Close();
    }

但我真的应该这样做吗?还是我应该使用(SqlConnection conn = new SqlConnection(cCon.getConn()))?请帮助我理解这一点。我原来做的方式有那么错吗?

SqlConnection conn = new SqlConnection(cCon.getConn());
   using( SqlCommand cmd = new SqlCommand("sp_SaveSomething", conn))
{
    cmd.CommandType = CommandType.StoredProcedure;
    cmd.Parameters.Add(new SqlParameter("@x", xxx));
    cmd.Parameters.Add(new SqlParameter("@ORG", ORG));        
    try
    {
        conn.Open();
        cmd.ExecuteNonQuery();
    }
    catch (Exception ex)
    { }
    finally
    {
        conn.Close();
    }
}

【问题讨论】:

  • 你应该阅读这篇文章。它很好地解释了它; msdn.microsoft.com/en-GB/library/yh598w02.aspx。特别是,看一下代码 sn-p,它显示了编译器实际转换的“使用”语句。
  • try/catch/finally 是在 iDisposable 对象内部执行的,因此在这种情况下不需要执行 try/catch/finally。如果您有一些其他逻辑需要 catch/finally 用于其他目的,您可能仍然需要它。但是在这种情况下,您所做的基本上就是复制处置将为您做的事情。除了您在第二个代码示例中吞下任何有问题的错误外。 =)

标签: c# asp.net .net stored-procedures


【解决方案1】:

但我很难理解什么时候应该使用它们。

这很容易。每次处理实现 IDisposable 接口的类时,都应该使用它们。就像这样:

using (SqlConnection conn = new SqlConnection(cCon.getConn()))
using (SqlCommand cmd = conn.CreateCommand())
{
    conn.Open();
    cmd.CommandText = "sp_SaveSomething";
    cmd.CommandType = CommandType.StoredProcedure;
    cmd.Parameters.Add(new SqlParameter("@x", xxx));
    cmd.Parameters.Add(new SqlParameter("@ORG", ORG));        
    cmd.ExecuteNonQuery();
}

如果你想处理一些异常,你可以将你想处理的代码包装在 try/catch 语句中:

try
{
    using (SqlConnection conn = new SqlConnection(cCon.getConn()))
    using (SqlCommand cmd = conn.CreateCommand())
    {
        conn.Open();
        cmd.CommandText = "sp_SaveSomething";
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.Add(new SqlParameter("@x", xxx));
        cmd.Parameters.Add(new SqlParameter("@ORG", ORG));        
        cmd.ExecuteNonQuery();
    }
}
catch (Exception ex)
{
    // do something here with the exception, don't just consume it,
    // otherwise it's meaningless to catch it
}

如您所见,所有 IDisposable 资源(此代码 sn-p 中的 SqlConnection 和 SqlCommand)现在都正确包装在 using 语句中,这保证即使抛出异常也能正确处理它们。因此,您不再需要使用 finally 语句并明确地执行此操作。

还请记住,ADO.NET 使用connection pool,这意味着当您在 SqlConnection 上调用 .Open() 方法时,您并没有打开到数据库的物理连接。您只是从池中抽出一个。当您调用 .Close(或 .Dispose)方法时,您并没有关闭连接。您只是将其返回到连接池以便可以重复使用。

【讨论】:

  • 但是 conn 和 cmd 都是一次性的?对?我在 using 语句中包含哪一个? :)
  • 他们两个。看我的回答。
  • 谢谢!所以在这种情况下,我仍然使用 conn.Open(),但是当它到达 using 块的末尾时它会自动关闭?对吗?
  • 虽然从技术上讲,您并没有打开新的物理连接,但我认为有某种重置过程 (sp_reset_connection) 被调用,可确保删除任何本地临时表等。请参阅:@987654322 @
  • @DarinDimitrov 所以如果我们使用 using 块,它在代码中会是多余的,对吧?就像做 CRUD 操作一样,我们总是做“使用 conn”和“使用 cmd”对吗?或者有没有办法避免这种冗余?
【解决方案2】:

如果你把它放入 using 块,你就不必关闭连接。 Using 块用于实现 IDisposable 的对象。 IDisposable 允许对象在被 GC 收集之前清除非托管资源。这释放了内存并允许 GC 收集该对象。

【讨论】:

    【解决方案3】:

    using 块只是一个 try/finally 子句,具有自动关闭和处置一次性对象的功能。仅当您计划以某种方式处理抛出的异常时,才添加内部 try/catch。在您的示例中,您在 catch 块中什么都不做,因此没有必要。

    SqlCommand 和 SqlConnection 都是一次性的,所以你的代码应该改为

    using(SqlConnection conn = new SqlConnection(cCon.getConn())
    using( SqlCommand cmd = new SqlCommand("sp_SaveSomething", conn))
    {
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.Add(new SqlParameter("@x", xxx));
        cmd.Parameters.Add(new SqlParameter("@ORG", ORG));        
        conn.Open();
        cmd.ExecuteNonQuery();
    }
    

    【讨论】:

      【解决方案4】:

      实际上,这里应该有几个 using 块,因为 SqlConnectionSqlCommand 都实现了 IDisposable。而using 还负责在最后关闭连接,因此显式的conn.Close(); 变得不必要了。

          using (SqlConnection conn = new SqlConnection(cCon.getConn()))
          using (SqlCommand cmd = new SqlCommand("sp_SaveSomething", conn))
          {
              cmd.CommandType = CommandType.StoredProcedure;
              cmd.Parameters.Add(new SqlParameter("@x", xxx));
              cmd.Parameters.Add(new SqlParameter("@ORG", ORG));
              try
              {
                  conn.Open();
                  cmd.ExecuteNonQuery();
              }
              catch (Exception ex)
              {
                  // Log error, etc.
              }
          }
      

      【讨论】:

        【解决方案5】:

        会这样:

        using (SqlConnection conn = new SqlConnection(cCon.getConn()))
        {
            using (SqlCommand cmd = new SqlCommand("sp_SaveSomething", conn))
            {
                conn.Open();
                cmd.CommandType = CommandType.StoredProcedure;
                cmd.Parameters.Add(new SqlParameter("@x", xxx));
                cmd.Parameters.Add(new SqlParameter("@ORG", ORG));        
        
                cmd.ExecuteNonQuery();
            }
        }
        

        由于SqlConnectionSqlCommand 实现IDisposable 接口,using 块将处理CloseDispose 方法。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-12-01
          • 1970-01-01
          • 1970-01-01
          • 2010-12-11
          • 1970-01-01
          • 2015-05-20
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多