C# 为什么对SqlTransaction使用using语句?

C# 为什么对SqlTransaction使用using语句?,c#,using-statement,C#,Using Statement,我在代码中使用的SqlTransaction遇到了一些问题。在我的谷歌搜索过程中,我看到许多人将using语句与SqlTransaction一起使用 在SqlTransaction中使用这种类型的语句有什么好处和/或区别 using (SqlConnection cn = new SqlConnection()) { using (SqlTransaction tr = cn.BeginTransaction()) { //some code tr.C

我在代码中使用的SqlTransaction遇到了一些问题。在我的谷歌搜索过程中,我看到许多人将using语句与SqlTransaction一起使用

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

using (SqlConnection cn = new SqlConnection())
{
     using (SqlTransaction tr = cn.BeginTransaction())
     {
      //some code
      tr.Commit();
     }
}
当前我的代码如下所示:

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;
}

一种方法相对于另一种方法的优点是什么?

每次创建在块范围内实现
IDisposable
的类实例时,都应该使用
using
语句。它确保将对该实例调用
Dispose()
方法,无论是否引发异常

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

正确的方法是:

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

请注意,如果您的类具有实现
IDisposable
的类型的实例成员,则您的类必须实现
IDisposable
本身,并在自己的
dispose()
调用过程中释放这些成员。

如果不使用using()块,则必须显式调用.dispose()SqlConnection和SqlTransaction对象的方法。如果您未能做到这一点,则非托管资源将不会被释放,并可能导致内存泄漏或其他问题。

原因是,如果SqlTransaction对象未明确提交(例如,如果引发异常),它将在其Dispose()方法中回滚。换句话说,它与您的代码具有相同的效果,只是稍微干净了一点。

正在为您关闭并处理您的连接和事务。这相当于在您的try/catch上有一个finally块来进行处理

你也可以像这样压缩使用块

using (SqlConnection cn = new SqlConnection())
using (SqlTransaction tr = cn.BeginTransaction())     
{
      //some code
      tr.Commit();
}
这大致与:

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

    //some code
    tr.Commit();
}
finally
{
    if (cn != null)
        cn.Dispose();
    if (tr != null)    
        tr.Dispose();
}

Using语句是正确处理资源的简写。您可以在

中找到更多信息。最后,
使用
只是模式的快捷方式。但这是一个非常有用和有用的快捷方式,因为它可以确保您正确地实现模式,并意味着您可以用更少的代码来实现它


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

本质上,使用与您所做的操作相同,只是在finally块中加int,而不是捕获所有异常:

using (SqlConnection cn = new SqlConnection())
{
     using (SqlTransaction tr = cn.BeginTransaction())
     {
      //some code
      tr.Commit();
     }
}
与相同,只是代码要少得多:)



使用在代码返回后将释放连接对象的保证。Dispose对于释放非托管资源非常有用,作为一种良好的实践,如果对象实现IDisposable,则应始终调用Dispose方法。除此之外,它还美化了代码。7行代码看起来比14行代码好吗?每当我看到一块正在使用的石块时,我都会松一口气。这就像是从那令人愉快的气味中喷出的一缕薄雾。嗯,我是一个相当高效的代码块。看看我对内存的管理有多好,我的眼睛有多好看。

…因为它保证了无论代码中发生了什么,都会调用正在实现的IDisposble接口的“Dispose”方法。+1,通常是正确的,但不能总是使用using语句,有时需要自己实现IDisposable。我会说:“只要可能”,这意味着“只要创建一个IDisposable实例只在一个集团内使用”或类似的东西。是的,如果在
提交之前对
SqlTransaction
调用
Dispose
,那么事务将回滚。当然,如果在块中抛出异常而未处理,则将调用
Dispose
。我们是否必须在catch中显式声明tran.rollBack(),或者这将由使用块处理?@ZoHas它将在Dispose中处理不会导致内存泄漏,但可能会导致资源泄漏。。。。这会让你更快更糟。非常接近,但还有一个额外的匿名作用域块。您拥有的代码不会编译,因为cn和tr在finally块中超出范围。@ZoHas它将在
Dispose()处自动回滚Commit()使用(x=new x)使用(y=new y){}
只是显式的,这与我们总是在所有if语句周围放大括号的原因相同,即使它们是一行,你也应该做
cn.Open()
之前执行代码>否则您将收到InvalidOperationException。或者我是否遗漏了什么?通过反编译来确认这一点。在此.Dispose()上调用this.Rollback()。实际上,是否在Dispose()内调用Rollback取决于您使用的驱动程序的实现(请参阅).Driver实现程序应该调用Rollback,但Microsoft建议不要指望它。因此,如果您知道您将使用的唯一驱动程序在Dispose()中调用Rollback,则您是安全的。否则,显式调用它更安全。
{
    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();
        }
    }
}