如何在.NET中对多个SqlConnections使用单个SqlTransaction? 我有SQL Server 2000,它不支持多个活动结果 我必须做多次插入,每次插入一个连接 我希望在所有插入之前开始一个事务,并在所有插入之后完成它 我该怎么做

如何在.NET中对多个SqlConnections使用单个SqlTransaction? 我有SQL Server 2000,它不支持多个活动结果 我必须做多次插入,每次插入一个连接 我希望在所有插入之前开始一个事务,并在所有插入之后完成它 我该怎么做,.net,sql,sql-server,sql-server-2000,transactions,.net,Sql,Sql Server,Sql Server 2000,Transactions,您没有指定是否正在使用.NET2.0,但我会做出这样的假设。C#3.0示例代码如下所示: using (var tx = new TransactionScope()) { // Execute multiple DB statements inside here ts.Complete(); } 如果任何DB语句失败,将永远不会到达ts.complete,并且事务将在using语句结束时自动回滚。但是,这种方法的一个警告是,如果使用多个连接,最终会利用DTC,这意味着性能会降

您没有指定是否正在使用.NET2.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();
}

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


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

事务是在一个连接上创建的,在创建它们的连接之外没有作用域,因此您无法按要求执行。重构,以便您可以在连接上按顺序执行插入,而不是同时执行,或者实现不同的机制以实现回滚(例如,插入键表,可以用作查找,以便在以后的过程中遇到错误时删除插入的记录)您不使用一个连接和多个命令(实际上是在循环中重新创建的一个命令)的原因是什么? 也许这个解决方案适合您:

   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();
                }
            }
        }
    }
publicstaticvoidcommandexeconquery(sqlcommandcmd,
字符串查询,SqlParameter[]prms)
{
cmd.CommandText=查询;
cmd.Parameters.AddRange(prms);
cmd.ExecuteNonQuery();
cmd.Parameters.Clear();
}
静态void Main(字符串[]参数)
{
字符串插入查询=
@“插入测试表(第1列,第2列)”+
“值(@ParamCol1,@ParamCol2)”;
使用(SqlConnection连接=
新的SqlConnection(connectionString))
{
使用(SqlCommand命令=
connection.CreateCommand())
{
SqlTransaction=null;
尝试
{
//BeginTransaction()需要打开连接
connection.Open();
事务=连接。BeginTransaction();
//将事务分配给命令
command.Transaction=事务;
对于(int i=0;i<100;i++)
commandexeconquery(命令,insertQuery,
新的SqlParameter[]{
新的SqlParameter(“@ParamCol1”,i),
新的SqlParameter(“@ParamCol2”,i.ToString())});
Commit();
}
抓住
{
transaction.Rollback();
投掷;
}
最后
{
connection.Close();
}
}
}
}
另请参见

Sql Server 2000中是否有多个连接的替代方案?我知道SQLServer2005支持M.A.R.S,但2000不支持。SqlTransaction没有公共构造函数。我知道创建实例的唯一方法是使用SqlConnection.BeginTransaction方法,它不是静态的。@Jader:你说得对,我的意思是使用TransactionScope。后期编辑。此外,您可以使用同一连接执行多个命令并存储结果。我将再次更新帖子…Sql Server 2000不支持MultipleActiveResultSet。因此,我必须为每次插入创建一个连接。@JaderDias MARS不是重用单个
IDbConnection
和多个
IDbCommand
s所必需的。事实上,如果您使用的是SqlClient,ADO的连接池将有效地使您重用与数据库的相同连接,即使您的代码似乎要关闭并重新打开连接。我认为这在Sql Server 2000上是不可能的。最好使用using语句而不是显式的catch/finally来处理SqlTransaction。如果事务尚未提交,则处理事务将回滚。这是可能的,贾德。我已经用SQL 8.00.194对它进行了测试。乔,你说得对,SqlTransaction可能会按照你描述的方式使用。不过我还是更喜欢异常处理,它更灵活。你能发布一些代码吗?我知道2k不支持MultipleActiveResults,但这只对连接上的同时批处理很重要,你当然可以在给定的连接上用一个命令对象多次执行。Jader,我同意Cmsjr,使用SQL 8.00.194测试的单个案例。您的代码可能是特定的,但我们需要更多信息。