【问题标题】:How to use a single SqlTransaction for multiple SqlConnections in .NET?如何在 .NET 中为多个 SqlConnections 使用单个 SqlTransaction?
【发布时间】:2010-10-11 19:34:39
【问题描述】:
  1. 我有 SQL Server 2000,它不支持 MultipleActiveResults
  2. 我必须进行多次插入,每次插入一个连接即可完成。
  3. 我想在所有插入之前开始一个事务并在所有插入之后完成它。
  4. 我该怎么做?

【问题讨论】:

  • 您能否发布一些代码,我知道 2k 不支持 MultipleActiveResults,但这仅对连接上的同时批处理很重要,您当然可以在给定的命令对象上多次执行连接。
  • Jader,我同意 Cmsjr,用 SQL 8.00.194 测试了单例。您的代码可能是特定的,但我们需要更多信息。

标签: .net sql sql-server sql-server-2000 transactions


【解决方案1】:

您没有指定是否使用 .NET 2.0,但我会做出这样的假设。 C# 3.0 示例代码如下:

using (var tx = new TransactionScope()) {
    // Execute multiple DB statements inside here
    ts.Complete();
}

如果任何 DB 语句失败,将永远无法到达 ts.complete,并且事务将在 using 语句结束时自动回滚。但是,对这种方法的一个警告是,如果您使用多个连接,您最终将利用 DTC,这意味着性能较慢。

修改为将 SqlTransaction 更改为 TransactionScope

强制单个 SQL 连接以避免使用 DTC 的示例:

using (var tx = new TransactionScope())
using (var db = new SqlConnection(connString)) {
    // Command 1
    using (var cmd = db.CreateCommand()) {
        cmd.CommandText = "select...";
        using (var reader = cmd.ExecuteReader()) {
           // Process results or store them somewhere for later
        }
    }

    // Command 2
    using (var cmd = db.CreateCommand()) {
        cmd.CommandText = "select...";
        using (var reader = cmd.ExecuteReader()) {
           // Process results or store them somewhere for later
        }
    }

    // Command 3
    using (var cmd = db.CreateCommand()) {
        cmd.CommandText = "select...";
        using (var reader = cmd.ExecuteReader()) {
           // Process results or store them somewhere for later
        }
    }
    tx.Complete();
}

【讨论】:

  • Sql Server 2000 中多个连接的替​​代方法?我知道 Sql Server 2005 支持 M.A.R.S,但 2000 不支持。
  • SqlTransaction 没有公共构造函数。我知道创建实例的唯一方法是使用 SqlConnection.BeginTransaction 方法,它不是静态的。
  • @Jader:你说得对,我的意思是使用 TransactionScope。帖子已编辑。
  • 另外,您可以使用同一连接执行多个命令并存储结果。我会再次更新帖子...
【解决方案2】:

我认为一个事务不能跨越多个连接。

在不同的连接中进行多次插入的原因是什么?我认为您通常希望它们在一个连接中。

【讨论】:

  • Sql Server 2000 不支持 MultipleActiveResultSets。所以我必须为每次插入创建一个连接。
  • @JaderDias MARS 不需要重复使用单个 IDbConnection 和多个 IDbCommands。事实上,如果您使用 SqlClient,ADO 的连接池将有效地使您重用与数据库的相同连接,即使您的代码似乎关闭并重新打开连接。
【解决方案3】:

事务是在连接上创建的,并且没有超出创建它们的连接的范围,因此您无法按照您的要求进行操作。重构,以便您可以在连接上按顺序执行插入,而不是同时执行,或者实现不同的机制来实现回滚(例如,插入键的表可以用作查找以在稍后遇到错误时删除插入的记录过程)

【讨论】:

    【解决方案4】:

    您不使用一个连接和多个命令(实际上是在循环中重新创建一个命令)的原因是什么? 也许这个解决方案对你有用:

       public static void CommandExecNonQuery(SqlCommand cmd, 
           string query, SqlParameter[] prms)
        {
            cmd.CommandText = query;
            cmd.Parameters.AddRange(prms);
            cmd.ExecuteNonQuery();
            cmd.Parameters.Clear();
        }
    
        static void Main(string[] args)
        {
            string insertQuery = 
               @"INSERT TESTTABLE (COLUMN1, COLUMN2) " + 
                 "VALUES(@ParamCol1, @ParamCol2)";
            using (SqlConnection connection = 
              new SqlConnection(connectionString))
            {
                using (SqlCommand command = 
                  connection.CreateCommand())
                {
                    SqlTransaction transaction = null;
                    try
                    {
                        // BeginTransaction() Requires Open Connection
                        connection.Open();
    
                        transaction = connection.BeginTransaction();
    
                        // Assign Transaction to Command
                        command.Transaction = transaction;
                        for (int i = 0; i < 100; i++)
                            CommandExecNonQuery(command, insertQuery, 
                              new SqlParameter[] { 
                                new SqlParameter("@ParamCol1", i), 
                                new SqlParameter("@ParamCol2", i.ToString()) });
                        transaction.Commit();
                    }
                    catch
                    {
                        transaction.Rollback();
                        throw;
                    }
                    finally
                    {
                        connection.Close();
                    }
                }
            }
        }
    

    另见
    Sql Server Transactions - ADO.NET 2.0 - Commit and Rollback - Using Statement - IDisposable

    【讨论】:

    • 我认为在 Sql Server 2000 上是不可能的。
    • 最好使用 using 语句而不是显式的 catch/finally 来处理 SqlTransaction。如果尚未提交事务,则处置事务会将其回滚。
    • 有可能,杰德。我已经用 SQL 8.00.194 对其进行了测试
    • Joe,你说得对,SqlTransaction 可以按照你描述的方式使用。我还是更喜欢异常处理,它更敏捷。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-08
    • 2022-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多