1

我在 vb.net 中开始交易。我在 SQL Server 2008 上执行了一个存储过程。该存储过程包含BEGIN TRANSACTION. 它失败了,并且ROLLBACKCATCH块运行中......

BEGIN CATCH

    IF @@TRANCOUNT > 1 ROLLBACK
        EXEC p_RethrowError

END CATCH

Rethrow 有效地执行了“raiserror”。

执行传回 vb.net。“Catch sqlException”中的回滚执行。

问题:

  • 为什么是@@TRANCOUNT1 而不是 2?(即为什么begin trans不包括在 vb.net 中?)

  • 为什么ROLLBACK在 SQL 中也不回滚客户端传输(但在客户端回滚确实回滚 SQL Server)?

最后,在 vb.net 中,如果您尝试在客户端内两次回滚事务,则会收到异常“事务已完成”。是否知道交易是否已完成或仍在等待中?谢谢。

------------ VB.Net代码

Public Sub sub1(ByVal intID As Integer,  ByVal intValue as integer, ByVal intAuditUser As Int16)


Dim objConn As New SqlConnection(GetDBaseConnectionString())

    objConn.Open()

    '***** start the transaction ************************************************'
    Dim objTrans As SqlTransaction = objConn.BeginTransaction()

    Try

        Call sub2(objTrans, intID, intValue, intAuditUser)

        '***** commit the transaction ************************************************'
        objTrans.Commit()

    Catch es As SqlException
        objTrans.Rollback()
        Throw es

    Catch ex As Exception
        '***** rollback the transaction ************************************************'
        objTrans.Rollback()
        Throw ex

    Finally
        If objConn.State <> ConnectionState.Closed Then objConn.Close()
    End Try

End Sub

Private Sub Sub2(ByVal objTrans As SqlTransaction, ByVal intID As Integer, ByVal intValue as integer, ByVal intAuditUser As Int16)

    Dim objParams As New List(Of SqlParameter)

        SqlHelper.AddInParameter(objParams, "ID", SqlDbType.Int, intID)
        SqlHelper.AddInParameter(objParams, "Value", SqlDbType.Int, intValue)
        SqlHelper.AddInParameter(objParams, "AuditUser", SqlDbType.SmallInt, intAuditUser)

        '* save details'
        SqlHelper.ExecuteNonQuery(objTrans, CommandType.StoredProcedure, "p_StoredProc_UpdateSomething", objParams.ToArray)

End Sub
4

2 回答 2

2

为什么@@TRANCOUNT 是 1 而不是 2?(即为什么不包括 vb.net 中的 begin trans ?)

它是 2。这就是它的记录方式,如果它不是 2,则服务器端ROLLBACK将不会执行。

为什么 SQL 中的 ROLLBACK 也不回滚客户端传输(但客户端中的回滚确实回滚 SQL Server)?

没有单独的客户端事务。它是所有相同的服务器端事务,并且无论当前的@@TRANCOUNT 值如何,也无论在何处启动回滚,它ROLLBACK总是回滚事务。

最后,在 vb.net 中,如果您尝试在客户端内两次回滚事务,则会收到异常“事务已完成”。

的实现SqlTransaction.Rollback非常复杂,对于僵尸事务,pre-SQL Server 2005 和 post-SQL Server 2005 有不同的路径,例如原始的 pre-2005 路径执行一个简单的Rollback调用,因此:

IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION

...并且SqlTransaction客户端对象还进入僵尸模式,这就是为什么您在随后尝试再次ROLLBACK在同一对象上执行后看到错误的原因。SqlTransaction

SQL Server 2008 上的代码路径类似,只是它不再基于人类可读的 SQL。

这解释了为什么您只会在第二次和后续调用时收到错误SqlTransaction.Rollback,即使回滚已经在存储过程中不可撤销地启动。

是否知道交易是否已完成或仍在等待中?

是的。方法见这里

获取与事务关联的 SqlConnection 对象,如果事务不再有效,则为 null。

因此,如果可以这样测试:

if (myTransaction.Connection != null) ...
于 2012-06-29T22:51:55.710 回答
0

嘿克里斯克里斯医生,

诚然,这与您最初的问题没有太大关系。但是,在阅读了您关于如何在 vb.net 中开始交易的评论之后。这可能会有所帮助:

Dim sqlUpdate As New StringBuilder 'use this to build your insert/update statements
sqlUpdate.Append("SQLCODE")
Dim cnADO As SqlClient.SqlConnection = yourDataBaseStuff.getConnection("targetServer", cnADO)
Dim trans As SqlTransaction = Nothing
Dim sqlCmdUpdate As New SqlCommand(sqlUpdate.ToString, cnADO)
sqlCmdUpdate.Parameters.AddWithValue("@X", new_x) 'where @X is your stored procedure variable, and new_x is what you would like to pass in


' Build Transaction, associate commands
trans = cnADO.BeginTransaction
cmdLoad.Transaction = trans
cmdLoad.CommandText = "Transaction stuff"
cmdLoad.ExecuteNonQuery()
sqlCmdUpdate.Transaction = trans
sqlCmdUpdate.ExecuteNonQuery()
trans.Commit()

希望这能让你朝着更好的方向开始!

-sf

于 2012-06-28T16:49:41.570 回答