【问题标题】:SqlCommand.Dispose() before SqlTransaction.Commit()?SqlTransaction.Commit() 之前的 SqlCommand.Dispose()?
【发布时间】:2012-03-07 01:07:03
【问题描述】:

在提交事务之前处理分配给事务的命令是否有效?我自己测试了以下代码,它似乎运行良好,但这是一个相当小的例子,所以如果有人肯定知道,我正在寻找确认。

internal static void TestTransaction()
{
    try
    {
        Program.dbConnection.Open();
        using (SqlTransaction transaction = Program.dbConnection.BeginTransaction())
        {
            Boolean doRollback = false;
            for (int i = 0; i < 10; i++)
            {
                using (SqlCommand cmd = new SqlCommand("INSERT INTO [testdb].[dbo].[transactiontest] (testvalcol) VALUES (@index)", Program.dbConnection, transaction))
                {
                    cmd.Parameters.AddWithValue("@index", i);
                    try
                    {
                        cmd.ExecuteNonQuery();
                    }
                    catch (SqlException)
                    {
                        doRollback = true;
                        break;
                    }
                }
            }
            if (doRollback)
                transaction.Rollback();
            else
                transaction.Commit();
        }
    }
    finally
    {
        Program.dbConnection.Close();
    }
}

【问题讨论】:

  • 您只是在处理 Command 对象,因为它包裹在 using(){} 周围事务与命令以及连接相关联..那么您将遇到灾难性错误..

标签: c# .net sql-server-2008 tsql


【解决方案1】:

连接、事务和命令对象只是将命令发送到数据库的工具。一旦命令被执行,数据库就会收到它。无论你之后对命令对象做什么,处理它,烧掉它,或者把它发射到月球上,这个事实都不会改变。 (只能回滚)。

您可以在一个SqlConnection(有或没有SqlTransaction)的范围内创建和处置任意数量的命令。您可以在一个SqlConnection 中启动和处理任意数量的事务。为了证明这一点,请参阅:

using (var conn = new SqlConnection(@"server=(local)\sql2008;database=Junk;Integrated Security=SSPI"))
{
  conn.Open();
  // Repeat this block as often as you like...
  using (var tran = conn.BeginTransaction())
  {
    using (var cmd = new SqlCommand("INSERT INTO Mess VALUES ('mess1')", conn, tran))
    {
      cmd.ExecuteNonQuery(); // Shows in Sql profiler
    }
    tran.Commit(); // Commits
  }
  using (var cmd = new SqlCommand("INSERT INTO Mess VALUES ('mess2')", conn))
  {
    cmd.ExecuteNonQuery(); // Executes and commits (implicit transaction).
  }
}

当然,对于健康的代码,您需要以正确的顺序处理所有对象。在释放SqlConnection 之后释放命令可能会导致连接对象留在内存中。

【讨论】:

  • 为什么以错误的顺序处理会导致连接留在内存中?我希望它至少会保留到最后一个命令/事务被处理。
  • @eFloh 因为它保留了对连接池底层连接的引用。它无法删除该引用,因为它还有一个未处理的命令。
  • 好的,我们的意思是一样的。 is 将在所有命令被释放时被释放,即使它们在连接使用结束后被释放。我首先理解你上面的文字意味着在这种情况下它永远不会被处理......
  • @eFloh 我知道几周前有一篇关于这个的帖子。终于找到了:stackoverflow.com/questions/8842115/…
【解决方案2】:

是的,它可能是安全的。 using() 正在关闭命令,而不是连接。

但是您应该将该 Connection 放在另一个 using() 块或 try/finally 构造中。

【讨论】:

    【解决方案3】:

    确认,这非常有效,而且(至少在我们公司)甚至被认为是正确的方法。

    1. 创建连接
    2. 创建交易
    3. 创建命令,使用事务,执行
    4. dispose 命令
    5. 提交交易
    6. 处理连接

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-20
      • 2011-03-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多