52

我遇到了一些关于我在代码中使用的 SqlTransaction 的问题。在我的谷歌搜索过程中,我看到很多人使用带有 SqlTransaction 的 using 语句。

将这种类型的语句与 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;
}

一种方式比另一种方式有什么优势?

4

8 回答 8

62

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

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

正确的做法是:

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

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

于 2009-07-14T20:30:21.547 回答
30

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

于 2009-07-14T20:32:18.767 回答
16

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

using (SqlConnection cn = new SqlConnection())
{
     using (SqlTransaction tr = cn.BeginTransaction())
     {
      //some code
      tr.Commit();
     }
}

是一样的,只是少了很多代码:)

{
    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();
        }
    }
}
于 2009-07-14T20:35:44.157 回答
9

说到底,using只是一种模式的捷径。但它是一个非常有用且有用的快捷方式,因为它可以确保您正确地实现该模式,并且意味着您可以用更少的代码来完成它。

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

于 2009-07-14T20:34:22.663 回答
4

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

你也可以像这样压缩 using 块......

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();
}
于 2009-07-14T20:32:24.710 回答
3

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

于 2009-07-14T20:31:03.200 回答
1

使用 using 保证您的连接对象将在代码返回后被释放。Dispose 对释放未管理的资源很有用,作为一个好习惯,如果对象实现了 IDisposable,则应始终调用 dispose 方法

于 2009-07-14T20:40:33.710 回答
1

除此之外,它还美化了您的代码。7行代码不比14行好看吗?每次看到 using 块时,我都会松一口气。就像从那个令人愉快的臭东西中喷出的小雾一样。嗯,我是一个非常高效的代码块。看看我对记忆的管理有多好,我有多赏心悦目。

于 2012-04-06T16:51:03.593 回答