经纪人服务交易管理

时间:2012-04-09 13:47:53

标签: sql-server-2008 service-broker

我正在实施许多SSB,处理两个不同的实例。它们是基于异步触发器的数据推送模式。

我的 SQL信息如下所示: Microsoft SQL Server Management Studio 10.50.2500.0 Microsoft Analysis Services客户端工具10.50.2500.0 Microsoft数据访问组件(MDAC)6.1.7601.17514 Microsoft MSXML 3.0 4.0 5.0 6.0 Microsoft Internet Explorer 9.0.8112.16421 Microsoft .NET Framework 2.0.50727.5448 操作系统6.1.7601

我的情景主要如下所示

  1. 多个记录 已插入 批量在表格或一个记录

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

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

  4. 验证此消息。

  5. 如果验证未成功,则消息从队列中删除 ACk 会被发送使用不同的SSB对象返回infrom消息无效。

  6. 否则,发送确认信息成功读取

  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. 最后,我发现之前的阅读成功结果并非“完全发送”第二次正常发送。

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

    • 我是否应该为每个分离的任务使用BEGIN TRAN并将其从接收和处理UPS中删除?

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

    • 我是否应该修改我的TRY,CATCH阻止ar接收以避免此问题

  13. 最后,我希望即使出现问题之后发送所有的ack并且想要避免Poison消息并且根本不回滚。 提前谢谢。

    -BTW我使用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
    

1 个答案:

答案 0 :(得分:3)

您正在使用旧式@@ ERROR检查混合BEGIN TRY / BEGIN CATCH块。这使得错误处理事务处理几乎无法管理。请考虑以下代码段:

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批处理消息,即使某些消息在处理过程中发生错误)。