1

2 つの異なるインスタンスで動作する多くの SSB を実装しています。これらは、非同期トリガーに基づくデータ プッシュパターンです。

私のSQL 情報は以下の通りです。 2.0.50727.5448 オペレーティング システム 6.1.7601

私のシナリオは主に以下のとおりです

  1. 複数のレコードは、テーブルまたは1 つのレコードに一括で挿入されます。

  2. このデータは別の DB に送信されます。

  3. アクティブ化手順は、 BEGIN TRAN と END TRAN の間で開始されます。

  4. このメッセージを検証します。

  5. 検証に失敗した場合は、このメッセージキューから削除し、別の SSB オブジェクトを使用してそのメッセージが無効であったことから、ACkを送り返します。

  6. それ以外の場合は、メッセージが正常に読み取られたことを知らせるACKが送信されます。

  7. 次に、Activation Procedure は別の Procedure を呼び出して、メッセージ body処理します。

  8. この USP_Process_Records もBEGIN TRAN と END TRAN の間にあります。

  9. 非常に多くの理由により、この手順は、私が行ったいくつかのビジネスニーズに従って失敗する可能性があります.

  10. Pro SQL Server 2008 Service Broker になります。

  11. したがって、アクティベーション手順では、 USP_Process_Records の失敗状態になる、 BEGIN CATCH 部分に移動してトランザクションをロールバックし、失敗 ACK を送信します

  12. 最後に、前の読み取り成功確認応答はまったく送信されず2 回目は正常に送信されることがわかりました。

    • そのため、Broker Service のトランザクション管理について非常に混乱しています。

    • 個別のタスクごとに BEGIN TRAN を使用し、受信および処理 UPS から削除する必要がありますか?

    • USP_Process_Records 内でも TRY、CATCH を使用して、USP_Receive_Records にエラーを返す必要がありますか?

    • この問題を回避するには、TRY、CATCH ブロック ar Receive を変更する必要があります

最後に、後で何か問題が発生した場合でもすべての ack を送信し、Poison メッセージとロールバックをまったく回避したいと考えています。前もって感謝します。

-ところで、私はrusanu ブログを Broker Service Error HandlingRead Pro SQL Server 2008 Service Broker Transaction Management 部分に使用しました。

以下の USP のサンプルを見つけてください。

--USP_Receive_Records

BEGIN TRY
BEGIN TRAN

        WHILE 1=1
        BEGIN
            SELECT @ReplyMessage = NULL, @TargetDlgHandle = NULL

            WAITFOR (RECEIVE TOP(1)
            @TargetDlgHandle=Conversation_Handle
            ,@ReplyMessage = CAST(message_body AS XML)
            ,@ReplyMessageName = Message_Type_Name
            FROM Q_Service_Receive), TIMEOUT 1000

            IF @TargetDlgHandle IS NULL 
            BREAK

            --Check if the message has the same message type expected
            IF @ReplyMessageName=N'Service_Msg'  
            BEGIN
                        --Send Batch Read Success ACK
                        --Send ACK Here
                        EXEC [dbo].[USP_ACKMsg_Send] @ACKMsg, @Service_Msg;
                        --Handle ACK Send failed!

                        -- Execute the USP_Service_Msg_Process for the batch rows
                        EXECUTE USP_Service_Msg_Process @ReplyMessageName, @RC OUTPUT;

                        --Case Processing Succeeded             
                        IF @RC=0
                        BEGIN
                            --Send Batch Read Success ACK
                        END

                        --SEND ACK Processing failed with Return Code to define cause of the error
                        ELSE
                        BEGIN
                            --Send Batch Processing Failed ACK
                        END

            END 
            END CONVERSATION @TargetDlgHandle;
        END
    COMMIT TRAN;
    END TRY

    BEGIN CATCH
    if (XACT_STATE()) = -1
        BEGIN
              rollback transaction;
        END;
    if (XACT_STATE()) = 1
        BEGIN
    DECLARE @error int, @message nvarchar(4000), @handle uniqueidentifier;
    SELECT @error = ERROR_NUMBER(), @message = ERROR_MESSAGE();
    END conversation @handle with error = @error description = @message;
    COMMIT;
        END
    END CATCH
END

--USP_Process_Records
BEGIN TRAN 
        While(@nCount <= @nodesCount)
        BEGIN

        IF(@S_HIS_Status = '02')
            BEGIN
                -- check N_Paid_Trans_ID is not nuul or zero or empty
                IF( @N_GET_ID IS NULL OR @N_GET_ID = 0 OR @N_GET_ID = '')
                    BEGIN
                        SET @RC = 8
                        RETURN;
                    END

                EXECUTE USP_Handle_Delivered_Service @N_GET_ID, @RC OUTPUT
                SELECT @myERROR = @@ERROR--, @myRowCount = @@ROWCOUNT
                IF @myERROR <> 0 OR @RC <> 0
                BEGIN
                    ROLLBACK TRAN
                END
            END

            --A lot of similar cases
END TRAN
4

1 に答える 1

3

BEGIN TRY/BEGIN CATCH ブロックと古いスタイルの @@ERROR チェックを混在させています。これにより、エラー処理トランザクション処理の両方を管理することがほとんど不可能になります。次のコード スニペットを検討してください。

SELECT @myERROR = @@ERROR--, @myRowCount = @@ROWCOUNT
IF @myERROR <> 0 OR @RC <> 0
BEGIN
   ROLLBACK TRAN
END

ここに含まれる制御フローとトランザクション フローをたどることができますか? コードは TRY/CATCH ブロックから呼び出されるコンテキストで実行されるため、@@ERROR ケースは発生せず、制御フローは CATCH ブロックにジャンプする必要があります。しかし、TRY/CATCH ブロックがないときにプロシージャが別のコンテキストから呼び出された場合はどうなるでしょうか。@@ERROR のケースを使用できますが、これは制御フローが継続することを意味します。TRY/CATCH コンテスト設定されている場合でも、@RC がゼロ以外の場合、トランザクションはロールバックされますが、制御フローは続行されますトランザクション全体がロールバックされたため、次のステートメントは、ステートメントごとのスタンドアロン トランザクションのコンテキストで実行されます。つまり、このような場合、受信していないメッセージに対して応答 Ack を送信できます (ロールバックしただけです!)。行動が不安定に見えるケースを見ているのも不思議ではありません。

エラー処理のスタイルは 1 つだけにしておくことをお勧めします (そして、正しいスタイルは BEGIN TRY/BEGIN CATCH ブロックだけです)。アプリケーション ロジック エラーが発生した場合に意図的にロールバックしないでください。代わりにRAISERROR、必要に応じてロールバックするために CATCH ブロックを使用してそれに依存してください。また、例外処理とネストされたトランザクションに示されているテンプレートの後に、プロシージャのスタイルを設定してください。このテンプレートにより、エラーが発生した場合にトランザクション内のセーフポイントにロールバックするメッセージごとの決定が可能になります (つまり、一部のメッセージで処理中にエラーが発生した場合でも、メッセージの RECEIVE バッチをコミットします)。

于 2012-04-09T17:53:04.250 に答える