1

I begin a transaction in vb.net. I execute a stored procedure on SQL Server 2008. That stored procedure contains BEGIN TRANSACTION. It fails, and ROLLBACK in CATCH block runs...

BEGIN CATCH

    IF @@TRANCOUNT > 1 ROLLBACK
        EXEC p_RethrowError

END CATCH

Rethrow effectively does a 'raiserror'.

Execution passes back to vb.net. Rollback in "Catch sqlException " executes.

Questions:

  • Why is @@TRANCOUNT 1 rather than 2? (i.e. how come begin trans in vb.net is not included?)

  • Why does ROLLBACK in SQL not rollback client trans as well (but a rollback in client does rollback SQL Server)?

And finally, in vb.net, if you try to rollback transaction twice within client, you get exception "transaction has completed". Is there anyway of knowing whether the transaction has completed, or is still pending? Thanks.

----------- VB.Net Code

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 が 2 ではなく 1 なのはなぜですか? (つまり、vb.net の begin trans が含まれていないのはなぜですか?)

それは 2 です。それが文書化されている方法であり、2 でない場合、サーバー側ROLLBACKは実行されません。

SQL の ROLLBACK がクライアント トランスもロールバックしないのはなぜですか (ただし、クライアントのロールバックは SQL Server をロールバックします)。

個別のクライアント側トランザクションはありません。これはすべて同じサーバー側トランザクションであり、現在の @@TRANCOUNT 値に関係なく、またロールバックが開始された場所に関係なく、ROLLBACK常にトランザクションをロールバックします。

最後に、vb.net で、クライアント内でトランザクションを 2 回ロールバックしようとすると、「トランザクションが完了しました」という例外が発生します。

の実装SqlTransaction.Rollbackは非常に複雑で、SQL Server 2005 以前と SQL Server 2005 以降ではゾンビ トランザクションのパスが異なります。たとえば、2005 年以前の元のパスは次のように単純なRollback呼び出しを実行します。

IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION

...さらに、クライアント側のオブジェクトがゾンビ モードに入ります。これが、同じオブジェクトに対して再度SqlTransaction実行を試みた後にエラーが発生した理由です。ROLLBACKSqlTransaction

SQL Server 2008 のコード パスは、人間が読める SQL に基づいていないことを除いて、似ています。

SqlTransaction.Rollbackこれは、ストアド プロシージャ内でロールバックが既に取り消し不能に開始されているにもかかわらず、2 回目以降の呼び出しでのみエラーが発生する理由を説明しています。

トランザクションが完了したか、まだ保留中かを知る方法はありますか?

はい。方法については、こちらを参照してください。

トランザクションに関連付けられた 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 に答える