删除有害消息

适用于SQL ServerAzure SQL 托管实例

病毒消息是包含应用程序无法成功处理的信息的消息。 例如,在更改订单使部件过时之前,制造工作站可能会提交从库存中撤回部件的请求。 对库存的请求正在传输中时,更改命令开始生效。 库存管理应用程序从工作站接收到请求,但无法成功处理请求,并且更新库存中部件数量的数据库操作失败。 然后,包含接收操作的事务将回滚,并将该消息返回到队列中。 在这种情况下,应用程序会继续收到这个消息,更新操作也将继续失败,然后该消息会再次返回到队列中。

病毒消息不是损坏的消息,可能不是无效的请求。 Service Broker 包含可检测损坏消息的消息完整性检查。 应用程序通常也会验证消息的内容,并放弃包含非法请求的消息。 相反,很多有害消息在它们被创建时是有效的,但之后却变成了无法处理的消息。

自动病毒消息检测

Service Broker 提供了有害消息自动检测功能。 当包含 RECEIVE 语句的事务回滚五次时,Service Broker 将通过自动将队列状态设置为 OFF禁用从中接收消息的所有队列。 此外,Service Broker 会生成一个类型为 Broker:Queue Disabled 的事件。

管理员可以使用 SQL Server 代理警报在禁用队列时收到通知。 开发人员也可以创建一个应用程序,检测 Service Broker 何时禁用队列。 该应用程序通常检查队列中的消息以查找有害消息。 应用程序在确定无法处理的消息后,会将队列状态设置为 ON,并因错误结束该消息的会话。 在结束会话时,检测有害消息的应用程序必须小心清除任何与该会话关联的状态。 有关创建应用程序以从病毒消息中恢复的详细信息,请参阅 “处理有害消息”。

管理删除有害消息

大多数应用程序都以编程方式跟踪和删除有害消息。 但是,有时可能需要手动删除病毒消息。 例如,执行恢复的应用程序的一部分可能无法检测病毒消息,或者可能无法安全地清理会话的已保存状态。

手动删除消息将面临中断重要会话的风险。 因此,请务必先检查有害消息,再从队列中删除消息。 若要查看消息的内容,请开始一个事务、接收消息正文、显示消息正文,然后回滚该事务。 在确认该消息是毒性消息之前,回滚事务是非常重要的。

示例

以下示例演示如何在队列 ExpenseQueue 中安全地检查会话句柄 e29059bb-9922-40f4-a575-66b2e4c70cf9 的消息。> [!注意]
> 本文中的代码示例是使用示例数据库进行测试的 AdventureWorks2025 ,可以从 Microsoft SQL Server 示例和社区项目 主页下载该数据库。

USE AdventureWorks2008R2;
GO

-- Sample to show the content of a message, then return
-- the message to the queue. This may be useful to determine
-- whether a specific message cannot be processed due to the
-- content of the message.

-- Every exit path from the transaction rolls back the transaction.
-- This code is intended to inspect the message, not remove the
-- message from the queue permanently. The transaction must roll
-- back to return the message to the queue.
BEGIN TRANSACTION;

-- To print the body, the code needs the message_body and
-- the encoding_format.
DECLARE @messageBody AS VARBINARY (MAX),
    @validation AS NCHAR;

-- Receive the message. The WAITFOR handles the case where
-- an application is attempting to process the message when
-- this batch is submitted. Replace the name of the queue and
-- the conversation_handle value.
WAITFOR (RECEIVE TOP (1)
        @messageBody = message_body,
        @validation = validation
    FROM dbo.ExpenseQueue
    WHERE CONVERSATION_HANDLE = 'e29059bb-9922-40f4-a575-66b2e4c70cf9'),
TIMEOUT 2000;

-- Roll back and exit if the message is not available
-- in two seconds.
IF @@ROWCOUNT = 0
    BEGIN
        ROLLBACK TRANSACTION;
        PRINT 'No message available.';
        RETURN;
    END

      -- Print the message based on the encoding format of
      -- the message body.
IF (@validation = 'E')
    BEGIN
        PRINT 'Empty message.';
    END
ELSE IF (@validation = 'X')
        BEGIN
            PRINT CONVERT (NVARCHAR (MAX), @messageBody);
        END
ELSE IF (@validation = 'N')
        BEGIN
            PRINT 'No validation -- binary message:';
            PRINT @messageBody;
        END

ROLLBACK TRANSACTION;
GO

找到有害消息时,请结束相应的会话。 以下示例结束对话 e29059bb-9922-40f4-a575-66b2e4c70cf9:

-- End the conversation. Do this only if the message cannot be
-- processed by the normal procedure.
END CONVERSATION 'e29059bb-9922-40f4-a575-66b2e4c70cf9'
    WITH ERROR = 127 DESCRIPTION = N'Unable to process message.';
GO

会话结束时,Service Broker 将放弃该会话的所有消息。 通常处理消息的应用程序不会收到此会话的 EndDialog错误消息 。 因此,如果该应用程序维护状态,则您必须在结束会话并返回错误后,小心地删除与该会话关联的状态。

如果服务无法处理消息,这意味着服务无法完成会话的任务。 通过结束会话并返回一个错误,可以通知该会话的其他参与者该任务已失败。