病毒消息是包含应用程序无法成功处理的信息的消息。 例如,在更改订单使部件过时之前,制造工作站可能会提交从库存中撤回部件的请求。 对库存的请求正在传输中时,更改命令开始生效。 库存管理应用程序从工作站接收到请求,但无法成功处理请求,并且更新库存中部件数量的数据库操作失败。 然后,包含接收操作的事务将回滚,并将该消息返回到队列中。 在这种情况下,应用程序会继续收到这个消息,更新操作也将继续失败,然后该消息会再次返回到队列中。
病毒消息不是损坏的消息,可能不是无效的请求。 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 或 错误消息 。 因此,如果该应用程序维护状态,则您必须在结束会话并返回错误后,小心地删除与该会话关联的状态。
如果服务无法处理消息,这意味着服务无法完成会话的任务。 通过结束会话并返回一个错误,可以通知该会话的其他参与者该任务已失败。