Sql server 在VB.net和SQL Server 2008中开始事务

Sql server 在VB.net和SQL Server 2008中开始事务,sql-server,vb.net,sql-server-2008,transactionscope,Sql Server,Vb.net,Sql Server 2008,Transactionscope,我在vb.net中开始一个事务。我在SQLServer2008上执行一个存储过程。该存储过程包含开始事务。它失败,并且CATCH中的ROLLBACK块运行 BEGIN CATCH IF @@TRANCOUNT > 1 ROLLBACK EXEC p_RethrowError END CATCH Rethrow有效地执行“raiserror” 执行返回到vb.net。执行“Catch sqlException”中的回滚 问题: 为什么@@TRANCOUNT1而

我在vb.net中开始一个事务。我在SQLServer2008上执行一个存储过程。该存储过程包含
开始事务
。它失败,并且
CATCH
中的
ROLLBACK
块运行

BEGIN CATCH

    IF @@TRANCOUNT > 1 ROLLBACK
        EXEC p_RethrowError

END CATCH
Rethrow有效地执行“raiserror”

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

问题:

  • 为什么
    @@TRANCOUNT
    1而不是2?(也就是说,为什么vb.net中的
    begintrans
    不包括在内?)

  • 为什么SQL中的
    ROLLBACK
    不也回滚客户端事务(但客户端中的回滚会回滚SQL Server)

最后,在vb.net中,如果您尝试在客户端中回滚事务两次,则会出现异常“transaction has completed”。是否有必要知道交易是否已完成或仍处于未决状态?谢谢

-----------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
Public Sub sub1(ByVal intID为整数,ByVal intValue为整数,ByVal intAuditUser为Int16)
Dim objConn作为新的SqlConnection(getDBASconnectionString())
objConn.Open()
“******启动事务***************************************************************************”
Dim objTrans As SqlTransaction=objConn.BeginTransaction()
尝试
调用sub2(objTrans、intID、intValue、intAuditUser)
“******提交事务********************************************************”
objTrans.Commit()
捕获作为SqlException的事件
objTrans.Rollback()
掷骰子
特例
“******回滚事务*********************************************************”
objTrans.Rollback()
投手
最后
如果objConn.State ConnectionState.Closed,则objConn.Close()
结束尝试
端接头
Private Sub Sub2(ByVal objTrans作为SqlTransaction,ByVal intID作为Integer,ByVal intValue作为Integer,ByVal intAuditUser作为Int16)
将对象参数作为新列表(SqlParameter的)进行调整
SqlHelper.AddInParameter(objParams,“ID”,SqlDbType.Int,intID)
SqlHelper.AddInParameter(对象参数,“值”,SqlDbType.Int,intValue)
SqlHelper.AddInParameter(objParams,“AuditUser”、SqlDbType.SmallInt、intAuditUser)
“*保存详细信息”
SqlHelper.ExecuteOnQuery(objTrans,CommandType.StoredProcess,“p_StoredProc_updateMething”,objParams.ToArray)
端接头

嘿,克里斯医生

诚然,这与你最初的问题没有多大关系。但是,在阅读您关于如何在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()
希望这能让你从一个更好的方向开始

-科幻小说

为什么@TRANCOUNT是1而不是2?(即,如何开始转换 不包括vb.net吗?)

是2。就是这样,如果不是2,服务器端
回滚将不会执行

为什么SQL中的回滚不同时回滚客户端事务(而是 在客户端回滚(是否回滚SQL Server)

没有单独的客户端事务。它是所有相同的服务器端事务,并且无论当前的@tracount值是多少,也不管回滚从何处启动,都始终是事务

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

SqlTransaction.Rollback
的实现相当复杂,僵尸事务的路径不同,SQL Server 2005之前和SQL Server 2005之后,例如原始的2005之前路径执行一个简单的
Rollback
调用,因此:

IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION
…并且
SqlTransaction
客户端对象还进入了僵尸模式,这就是为什么您在随后再次尝试对同一
SqlTransaction
对象执行
ROLLBACK
后看到错误的原因

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

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

有吗 无论如何,我们都无法知道事务是否已完成,或者仍在进行中 待定

对。请参见以下内容:

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

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

if (myTransaction.Connection != null) ...

请添加一个代码示例,显示如何在vb中开始事务。netrollback不是transactionscope类上的一个方法,因此我不知道您是如何“在客户端内回滚两次”对不起,我没有说清楚-在这个特定示例中,我没有回滚客户端;然而,我试图编写防御代码,并想知道是否有诸如“if transaction.pending then rollback”这样的语句。但仅在防御性编码方面,以防万一,无论出于何种原因,其他地方的另一个例程已经回滚(但在本例中没有)。意思是说,在这个特定示例中,我不会在代码块中“两次”回滚客户端,p_RethrowError仅在@tracount>1时执行,但您会问为什么@tracount=1?p_RethrowError是否未执行?你有错误吗?谢谢@Sacredfaith;我们曾经做过类似的事情,但现在我们只使用企业库sqlhelper now(参见代码):使事情变得更简单、更快捷,这非常有用。你说得对,@@trancount是2。事实上,奇怪的是,当我在存储过程中没有begintrans(但在客户机中有一个)时,出于某种原因,trancount仍然是2。关于回滚(一个在客户机中,一个在服务器中)-我理解您关于不在客户机中开始回滚的意思:我的意思是,正如您所知道的,回滚是在客户机中调用的。我的意思是,若存储过程执行两次回滚,则在第二次回滚时会出现异常,但我认为不会调用回滚