为什么使用带有SqlTransaction的using语句?

MDS*_*ens 47 c# using-statement

我一直在遇到一些与我在我的代码中使用的SqlTransaction有关的问题.在我的谷歌搜索期间,我看到许多人使用带有SqlTransaction的using语句.

使用SqlTransaction这种类型的语句有什么好处和/或区别?

using (SqlConnection cn = new SqlConnection())
{
     using (SqlTransaction tr = cn.BeginTransaction())
     {
      //some code
      tr.Commit();
     }
}
Run Code Online (Sandbox Code Playgroud)

目前我的代码如下所示:

SqlConnection cn = new SqlConnection(ConfigurationManager.AppSettings["T3"]);
cn.Open();
SqlTransaction tr = cn.BeginTransaction();

try
{
     //some code
     tr.Commit();
     cn.Close();
}
catch(Exception ex)
{
      tr.Rollback();
      cn.Close();
      throw ex;
}
Run Code Online (Sandbox Code Playgroud)

一种方式优于另一种方式的优势是什么?

Joh*_*ers 57

一个using语句应该被用来每次创建一个实现类的实例时间IDisposable 块的范围之内.它确保Dispose()在该实例上调用该方法,无论是否抛出异常.

特别是,您的代码仅捕获托管异常,然后通过抛出新异常而不是重新抛出现有异常来销毁堆栈帧.

正确的方法是:

using (SqlConnection cn = new SqlConnection(ConfigurationManager.AppSettings["T3"])) {
    cn.Open();
    using (SqlTransaction tr = cn.BeginTransaction()) {
        //some code
        tr.Commit();
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,如果您的类具有实现类型的实例成员IDisposable,那么您的类必须实现IDisposable自己,并在其自己的Dispose()调用期间处置这些成员.

  • 我们是否必须在catch中显式声明tran.rollBack()或者是否由using块处理? (11认同)
  • ....因为它保证将调用正在实现的IDisposble接口的"Dispose"方法 - 无论您的代码中发生什么. (3认同)
  • +1,一般都是正确的,但你不能_always_使用using语句,有时你需要自己实现IDisposable.我会说:"只要有可能",这意味着"每当创建一个仅在一个集团内使用的IDisposable实例"或类似的东西时. (3认同)
  • 是的,如果在`Commit`之前在`SqlTransaction`上调用`Dispose`,那么事务将被回滚.当然,如果块内抛出异常而未处理,则会调用`Dispose`. (3认同)
  • 是啊.:-) (2认同)
  • @Downvoter:小心地说为什么?否则,你就无关紧要了。 (2认同)
  • @ZoHas将在Dispose中处理 (2认同)

Ken*_*nan 28

这样做的原因是,如果没有显式提交,SqlTransaction对象将在其Dispose()方法中回滚(例如,如果抛出异常).换句话说,它与您的代码具有相同的效果,只是更清洁一点.

  • 实际上,是否在Dispose()内部调用Rollback取决于您正在使用的驱动程序的实现(请参阅http://msdn.microsoft.com/en-us/library/bf2cw321(v=vs.110). ASPX).驱动程序实现者应该调用Rollback,但Microsoft建议不要指望它.因此,如果您知道您将使用的唯一驱动程序,则在Dispose()中调用Rollback是安全的.否则,显式调用它会更安全. (6认同)
  • 通过反编译确认了这一点.在this.Dispose()上调用this.Rollback(). (3认同)

hea*_*vyd 15

本质上,using使用与你正在做的相同的事情,除了int finally块而不是捕获所有异常:

using (SqlConnection cn = new SqlConnection())
{
     using (SqlTransaction tr = cn.BeginTransaction())
     {
      //some code
      tr.Commit();
     }
}
Run Code Online (Sandbox Code Playgroud)

是相同的,只是更少的代码:)

{
    SqlConnection cn = null;
    try
    {
       cn = new SqlConnection();
       {
           SqlTransaction tr = null;
           try
           {
               tr = cn.BeginTransaction())

               //some code
               tr.Commit();
            }
            finally
            {
                if(tr != null && tr is IDisposable)
                {
                    tr.Dispose();
                }
            }
        }
    }
    finally
    {
        if(cn != null && cn is IDisposable)
        {
            cn.Dispose();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 只是明确,同样的原因,我们总是围绕我们所有的if语句,即使它们是单行的 (3认同)
  • 你也应该在 `using (SqlTransaction tr ...` 之前执行 `cn.Open();`。否则你会收到 InvalidOperationException。或者我错过了什么? (2认同)

Joe*_*orn 6

最后,using只是模式的捷径.但它是一个非常有用且有用的快捷方式,因为它确保您正确实现模式并意味着您可以使用更少的代码来完成它.

在这种情况下,您尚未正确实现模式.如果调用tr.RollBack()也会引发异常,您的代码会发生什么?