【问题标题】:Broker Service Transaction Management经纪服务交易管理
【发布时间】:2012-04-21 21:12:06
【问题描述】:

我在两个不同的实例上实现了许多 SSB。它们是基于异步触发器的数据推送模式。

我的SQL Info如下图: Microsoft SQL Server 管理工作室 10.50.2500.0 Microsoft 分析服务客户端工具 10.50.2500.0 Microsoft 数据访问组件 (MDAC) 6.1.7601.17514 微软 MSXML 3.0 4.0 5.0 6.0 微软 Internet Explorer 9.0.8112.16421 微软 .NET 框架 2.0.50727.5448 操作系统 6.1.7601

我的场景主要如下图所示

  1. 多条记录插入批量在表中或一条记录

  2. 此数据被发送到另一个数据库。

  3. 激活过程开始在 BEGIN TRAN 和 END TRAN 之间

  4. 验证此消息。

  5. 如果验证不成功,则此消息从队列中删除并发送ACK使用不同的 SSB 对象返回该消息无效。

  6. 否则,发送 ACK 是因为消息读取成功

  7. 然后,激活过程调用另一个过程处理消息正文

  8. 此 USP_Process_Records 也在 BEGIN TRAN 和 END TRAN 之间

  9. 由于多种原因,此过程可能会根据我的某些业务需求而失败

  10. 要么是 Pro SQL Server 2008 Service Broker。

  11. 所以在激活过程中,它要么进入 USP_Process_Records 的失败条件,要么进入 BEGIN CATCH 部分并回滚事务并发送失败 ACK.

  12. 最后我发现前面的read success ack根本没有发送第二个发送正常。

    • 所以我对 Broker Service 中的事务管理感到非常困惑。

    • 我应该对每个单独的任务使用 BEGIN TRAN 并将其从 Receive and Process UPS 中删除吗?

    • 我是否也应该在 USP_Process_Records 中使用 TRY、CATCH 并将错误返回给 USP_Receive_Records?

    • 我是否应该修改我的 TRY、CATCH 块 ar Receive 以避免此问题

最后,我希望即使之后出现问题也能发送所有确认,并希望完全避免 Poison 消息和回滚。 提前致谢。

-顺便说一句,我已使用 rusanu 博客进行代理服务错误处理阅读 Pro SQL Server 2008 Service Broker 事务管理部分。

查找以下 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

【问题讨论】:

    标签: sql-server-2008 service-broker


    【解决方案1】:

    您将 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(您只是将其回滚!)。难怪您会看到行为似乎不稳定的情况。

    我建议您只坚持一种错误处理方式(唯一合理的方式是 BEGIN TRY/BEGIN CATCH 块)。不要在应用程序逻辑错误的情况下有意回滚,而是使用RAISERROR 并在必要时依赖 CATCH 块进行回滚。还要按照Exception handling and nested transactions 中显示的模板设置您的程序样式。此模板允许在发生错误时逐个消息决定回滚到事务中的安全点(即提交您的 RECEIVE 批消息,即使 一些 消息在处理过程中发生错误)。

    【讨论】:

    • 你是对的 Remus 我有两个问题: 1- 事务管理和嵌套事务 - 使用 Savepoint 和 @@trancount 检查 - 托管回滚并限制在 CATCH BLOCK 2- 混合错误处理 - 依赖现在在 TRY/CATCH 块上 - 在这种情况下很少使用 @@ERROR 检查而不是 ROLLBACK 性能得到增强并且毒药消息消失了 - 直到现在 :)- 谢谢 Remus,不知道该说什么 :) 来自埃及的问候
    猜你喜欢
    • 2016-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-28
    • 2021-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多