C# 在单个事务中发送多个SQL命令

C# 在单个事务中发送多个SQL命令,c#,.net,sql-server,C#,.net,Sql Server,我有一大堆插入到…字符串中。目前,我使用以下工具运行它们: using (SqlConnection connection = new SqlConnection(connectionString)) { connection.Open(); foreach (var commandString in sqlCommandList) { SqlCommand command = new SqlCommand(commandString, connectio

我有一大堆
插入到…
字符串中。目前,我使用以下工具运行它们:

using (SqlConnection connection = new SqlConnection(connectionString))
{
    connection.Open();
    foreach (var commandString in sqlCommandList)
    {
        SqlCommand command = new SqlCommand(commandString, connection);
        command.ExecuteNonQuery();
    }
}
我看到每个
ExecuteNonQuery()
也执行提交

  • 是否有办法在单个事务中插入所有行(最后提交)
  • 我想要单个事务的原因是为了加快“插入”过程。单笔交易是否也能让交易更快

  • 您可以对每种类型使用Parallel

       using (SqlConnection connection = new SqlConnection(connectionString))
        {
            List<string> sqlCommandList = new List<string>();
            connection.Open();
            Parallel.ForEach(sqlCommandList, commandString =>
            {
                SqlCommand command = new SqlCommand(commandString, connection);
                command.ExecuteNonQuery();
            });
        }
    
    使用(SqlConnection连接=新的SqlConnection(connectionString))
    {
    List sqlCommandList=新列表();
    connection.Open();
    Parallel.ForEach(sqlCommandList,commandString=>
    {
    SqlCommand=newsqlcommand(commandString,connection);
    command.ExecuteNonQuery();
    });
    }
    
    如果您在一个线程中执行多个查询,建议使用SQL transaction,您可以使用如下方式:

        SqlTransaction trans; 
    
        try
        {
            SqlConnection connection = new SqlConnection(connectionString);
            connection.Open();
    
            trans = connection.BeginTransaction(); 
    
            foreach (var commandString in sqlCommandList)
            {
                SqlCommand command = new SqlCommand(commandString, connection,trans);
                command.ExecuteNonQuery();
            }
    
            trans.Commit(); 
        }
        catch (Exception ex) //error occurred
        {
            trans.Rollback();
            //Handel error
        }
    

    仅使用一个事务和命令可能会获得一些性能,如下所示:

    using (SqlConnection connection = new SqlConnection(connectionString))
    {
       try
       {
          connection.Open();
    
          using (SqlTransaction trans = connection.BeginTransaction())
          {
              using (SqlCommand command = new SqlCommand("", connection,trans))
              {
                 command.CommandType = System.Data.CommandType.Text;
    
                 foreach (var commandString in sqlCommandList)
                 {
                    command.CommandText = commandString;
                    command.ExecuteNonQuery();
                 }
              }
    
              trans.Commit();
           }        
        }
        catch (Exception ex) //error occurred
       {
           //Handel error
       }
    }
    

    稍晚一点,但如果要将所有值插入到同一个表中,请将SQL insert编码为“insert into tablex(f1,f2,f3,…)值(@f1,@f2,@f3…)。创建命令并添加参数@F1…,然后在命令上设置Prepare标志。现在,当您在要插入的值列表中循环时,可以将它们设置为适当的参数,然后执行ExecuteOnQuery。SQL将预先解析命令字符串一次,然后每次使用新参数。这要快一点


    最后,您可以在一个命令中通过附加“;”来执行多个SQL语句如果必须执行整个字符串,则返回每个语句。您可以将这些命令组合在一起,并向SQL server发出一个执行它们的请求。

    您只需连接SQL并让服务器处理它:

    using (SqlConnection connection = new SqlConnection(connectionString))
    {
        string lsSql = string.Empty;
        foreach (var commandString in sqlCommandList)
        {
            lsSql = lsSql + commandString + " ; " + Environment.NewLine;
        }
    
        connection.Open();
        SqlCommand command = new SqlCommand(lsSql, connection);
        command.ExecuteNonQuery();
    }
    

    下面是我在日常工作中使用的内容,在使用foreach进行我需要在数据库上运行的任何非查询之前。您可以看到我正在使用OracleCommand,但如果需要,可以更改为SQL语句

    public static void ExecuteDatabaseNonQuery(字符串命令)
    {
    OracleCommand cmd=新的OracleCommand();
    cmd.Connection=conn;
    OracleTransaction;
    事务=conn.BeginTransaction(IsolationLevel.ReadCommitted);
    cmd.Transaction=Transaction;
    尝试
    {
    cmd.CommandText=命令;
    var update=cmd.ExecuteNonQuery();
    Commit();
    WriteLine(“{0}行已更新”,更新);
    }
    捕获(例外e)
    {
    transaction.Rollback();
    抛出新异常(“错误:+e”);
    }
    }
    

    注意:如果数据库上有任何未限制的更改,此方法将无限期等待

    SQlBulkCopy,您可以使用事务作用域(请参阅MSDN)。您可以使用并行each@Shyamsundarshah: 1. parallel.foreach在不同的线程上加载每个事务(每个线程将以提交结束,因此提交量相同)。2.我试过了,但插入的顺序有问题。一些插入发生在其他插入之前,并打破了我的外键限制。但是谢谢:-)1。parallel.foreach在不同的线程上加载每个事务(每个线程将以提交结束,因此提交量相同)。2.我试过了,但插入的顺序有问题。一些插入发生在其他插入之前,并打破了我的外键限制。但是谢谢:-)我会把
    命令放在行本身的
    try catch
    块,这样我就可以调用
    trans.Rollback()。无论如何,MS文档就是这样显示的。@Tony没有必要调用trans.rollback。如果SqlTransaction对象未显式提交(例如,如果引发异常),则该对象将在其Dispose()方法中回滚。请参阅下面的线程:@Gerardo H-但是,如果您显式调用它,1)如果
    Dispose
    停止为您调用rollback,您确信它已完成;2)发生回滚时,下一个开发人员很清楚。3) catch块还允许某些特定的错误记录。这些是否值得额外的混乱将因情况而异。我已经用过两种方法。是的,它会起作用,请注意添加必须提供给SPs的任何参数。“ExecuteOnQuery要求在分配给该命令的连接处于挂起的本地事务中时该命令具有事务。该命令的事务属性尚未初始化。”@Fernando68>>>SqlCommand=newSQLCommand(commandString,connection,trans);使用完SqlTransaction和SqlConnection对象后,不要忘记处理它们。危险地带!不
    使用
    意味着资源泄漏。这真的意味着所有语句都在同一事务中运行吗?如果是这样的话,你能告诉我文件上是怎么说的,或者提供证据吗?