交易错误——我是不是要求太多了?

Transaction Errors - Am I asking too much?

我 运行 在 vb.net 中执行以下循环,其中超过 1000 次迭代发出 1000 次更新命令:

Dim updateRoute As String = "UPDATE [Routes] SET [matching_route_id] = ? WHERE [ID] = ?"
Using transaction As OleDbTransaction = myconnection.BeginTransaction()
    Dim id As Integer
    For Each id In ids
        Using cmd2 As New OleDbCommand(updateRoute, myconnection)
            cmd2.Parameters.AddWithValue("?", id)
            cmd2.Parameters.AddWithValue("?", id)
            cmd2.ExecuteNonQuery()
        End Using
    Next
    transaction.Commit()
End Using

然而我收到以下异常

ExecuteNonQuery requires the command to have a transaction when the connection assigned to the command is in a pending local transaction. The Transaction property of the command has not been initialized.

这似乎告诉我,我需要在 cmd2 的每次迭代开始时开始交易。对我来说,这消除了使用交易的任何理由——因为我想作为一个大批量来做。即,事务应在第一个 UPDATE 之前开始并在最后一个 UPDATE 语句结束。

所以我想我的问题有两个方面:

  1. 如何让 vb.net 在循环前接受我的交易
  2. 或者,我如何 运行 像这样进行大批量更新。目前,一次更新一行几乎太慢了。

尝试将命令关联到事务,例如:

Using cmd2 As New OleDbCommand(updateRoute, myconnection, transaction)
    cmd2.Parameters.AddWithValue("?", id)
    cmd2.Parameters.AddWithValue("?", id)
    cmd2.ExecuteNonQuery()
End Using

另一方面,如果 Commit 使用 Try/Catch 块失败,您应该保证 RollBack,例如:

Using transaction As OleDbTransaction = myconnection.BeginTransaction()
    Try     
        Dim id As Integer
        For Each id In ids
            Using cmd2 As New OleDbCommand(updateRoute, myconnection, transaction)
                cmd2.Parameters.AddWithValue("?", id)
                cmd2.Parameters.AddWithValue("?", id)
                cmd2.ExecuteNonQuery()
            End Using
        Next
        transaction.Commit()
    Catch
        transaction.RollBack();
    End Try     
End Using

更新

我不确定,但如果您在数据库上进行单个查询,也许可以提高性能。或者,只需在每个 100 id 之间实现一个循环,并在每次点击一次时执行 100 更新,可以提高性能。

Using transaction As OleDbTransaction = myconnection.BeginTransaction()
    Try     
        Dim id As Integer
        Dim b As New StringBuilder()

        For Each id In ids
            b.AppendFormat("UPDATE [Routes] SET [matching_route_id] = {0} WHERE [ID] = {0}; ", id)
        Next

        Using cmd2 As New OleDbCommand(updateRoute, myconnection, transaction)              
            cmd2.ExecuteNonQuery()
        End Using
        transaction.Commit()
    Catch
        transaction.RollBack();
    End Try     
End Using

更好的 try catch 方法

      Using transaction As OleDbTransaction = myconnection.BeginTransaction()            
        Dim id As Integer
        Dim errors as Integer = 0

        For Each id In ids
            Using cmd2 As New OleDbCommand(updateRoute, myconnection, transaction)
                cmd2.Parameters.AddWithValue("?", id)
                cmd2.Parameters.AddWithValue("?", id)

                Try 
                  cmd2.ExecuteNonQuery()
                Catch
                  errors+=1
                End Try
            End Using
        Next

        If errors=0
          transaction.Commit()
        else
          transaction.RollBack();
        End If    
      End Using