【问题标题】:Transaction Errors - Am I asking too much?交易错误 - 我要求太多了吗?
【发布时间】:2016-03-21 18:01:38
【问题描述】:

我在 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 要求命令有一个事务,当 分配给命令的连接处于挂起的本地事务中。 该命令的 Transaction 属性尚未初始化。

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

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

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

【问题讨论】:

  • 每次迭代都不需要新命令,只需要新的参数值

标签: c# .net vb.net transactions ado.net


【解决方案1】:

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

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

【讨论】:

  • 不错!它有效,但过程仍然非常缓慢。有没有更好的方法来进行批量更新?
  • 也许您可以对存储过程进行一些改进,然后从 ado.net 中调用它。我从未尝试过使用 ado.net 的批量更新,但请看一下。 msdn.microsoft.com/en-us/library/kbbwt18a(v=vs.80).aspx
  • 是否可以创建一次cmd2 变量,然后将for 循环放在Using cmd2... 语句中?这样它只创建一次,但它的事务是在每次循环迭代时设置的
  • 如果这样做,则必须清除参数并替换为新值。我认为您可以访问数据库一次,但我不确定您是否可以取得良好的表现。我会更新的。
【解决方案2】:

尝试捕捉的更好方法

      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

【讨论】:

    猜你喜欢
    • 2019-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多