2014-09-23 414 views
2

我想测试第一个事务,如果它是成功的,那么我尝试第二个,如果第二个也是成功,那么我提交两者,如果第二个失败,我需要回滚第一个。事务回滚错误(此SqlTransaction已完成;它不再可用)

所以我有以下函数返回一个字典,可以是状态之一:

0(意为交易失败,但成功地回滚) - > SQL事务

1(指交易成功) - > SQL事务

-1(指交易失败,并没有管理回滚) - > SQL事务

Public Function execDBTrans_valMod(transactionName As String, ByVal emailSubject As String, ByVal emailBody As String, ByVal queryString As String, Optional ByVal connectionString As String = "SQLConnectionHere") As Dictionary(Of Integer, SqlTransaction) 
     Dim trans_dict As New Dictionary(Of Integer, SqlTransaction) 

     Using connection As New SqlConnection(ConfigurationManager.ConnectionStrings(connectionString).ToString) 'LATEST EXEC 
      connection.Open() 

      Dim command As New SqlCommand(queryString, connection) 
      Dim transaction As SqlTransaction = connection.BeginTransaction(transactionName) 
      command.Transaction = transaction 

      Try 
       command.CommandTimeout = 3600 'Used for large updates 
       command.ExecuteNonQuery() 
       'transaction.Commit() DO NOT COMMIT so that we can commit only after we verify that pbSite can be inserted 

       trans_dict.Add(1, transaction) 
       Return trans_dict 
      Catch dbTrans_ex As Exception 
       Try 
        transaction.Rollback() 

        trans_dict.Add(0, transaction) 
        Return trans_dict 
       Catch dbTrans2_ex As Exception 

        trans_dict.Add(-1, transaction) 
        Return trans_dict 
        ' This catch block will handle any errors that may have occurred on the server that would cause the rollback to fail, such as a closed connection. 
       End Try 
      End Try 

     End Using 
    End Function 

然后,我有一个函数如下代码:

Dim transPB_dict = execDBTrans_valMod("transPB", failSubject, failBody, buildInsert) 
If transPB_dict.ContainsKey(1) Then 'SUCCESS 

    Dim transPBsite_dict = execDBTrans_valMod("transPBsite", failSubject, failBody, buildInsert_PBsite) 

    If transPBsite_dict.ContainsKey(1) Then 
     transPB_dict.Item(1).Commit() 
     transPBsite_dict.Item(1).Commit() 
     Return True 
    Else 'Failed to create the tables for this user so rollback all the tables that were created in the previous transaction (all the old tables in panelbase) 
     transPB_dict.Item(1).Rollback() 'THIS THROWS THE ERROR This SqlTransaction has completed; it is no longer usable 

     Return False 
    End If 

Else 
     Return False 
End if 

我没有COMMITED第一笔交易的是,为什么它说,当我尝试回滚的SqlTransaction已完成......?

谢谢你的帮助!

回答

0

当您退出Using块

Using connection As New SqlConnection... 
End Using 

你的连接被关闭和处置,并反对任何未决的事务连接承诺。您不能针对多个连接进行相同的事务。

只创建并打开一次连接。将此连接(和事务)传递给要处理SQL的方法。然后当这一切完成后,您可以提交您的交易并关闭/处置您的连接。

处理跨多个SQL命令的单个连接会提高程序的速度,因为每个连接都会产生开销,从而降低速度。

+0

啊是有道理谢谢!我已将连接传回并手动关闭,而不是使用“使用”语句。 – Rezzy 2014-09-23 15:45:08

0

因为您的连接在execDBTrans_valMod中打开和关闭。
当连接关闭时,与连接关联的事务结束。

如果您需要在第二个命令失败时回滚第一个命令,则只需要一个事务。
连接和事务应由命令执行者的调用者管理。

你需要的东西,如:

Public Sub execDBTrans_valMod(ByVal transaction As SqlTransaction, ByVal emailSubject As String, ByVal emailBody As String, ByVal queryString As String) 
    Using command As New SqlCommand(queryString, transaction.Connection, transaction) 
     Try 
      command.CommandTimeout = 3600 'Used for large updates 
      command.ExecuteNonQuery() 
     Catch ex As Exception 
      ' Do something with emailSubject and emailBody?? 
      ' Then rethrow ex to be caught by the caller. 
      Throw 
     End Try 
    End Using 
End Sub 

,主叫方:当然

Using connection As New SqlConnection(ConfigurationManager.ConnectionStrings("SQLConnectionHere").ToString) 
    connection.Open() 
    Using transaction As SqlTransaction = connection.BeginTransaction() 
     Try 
      execDBTrans_valMod(transaction, failSubject, failBody, buildInsert) 
      execDBTrans_valMod(transaction, failSubject, failBody, buildInsert_PBsite) 
      transaction.Commit() 
      Return True 
     Catch ex As Exception 
      Try 
       transaction.Rollback() 
      Catch exRollback As Exception 
       ' Do logging or something when rollback failed. 
      End Try 
      Return False 
     End Try 
    End Using 
End Using