启用Service Broker需先执行ALTER DATABASE SET ENABLE_BROKER WITH ROLLBACK IMMEDIATE并验证sys.databases.is_broker_enabled=1;触发器中须用BEGIN DIALOG+TRY...CATCH发送XML消息;接收端必须配置ACTIVATION队列及配套存储过程,及时END CONVERSATION;备份恢复后需重新检查broker状态及跨实例三要素。

直接启用 Service Broker 并配好队列和服务,就能让 INSERT 操作不阻塞主业务。关键不是“能不能”,而是“对话建得快不快、消息收得稳不稳、激活过程扛不扛压”。
必须先确认数据库已启用 ENABLE_BROKER
Service Broker 默认是关闭的,ALTER DATABASE YourDB SET ENABLE_BROKER 是第一步,但容易踩两个坑:
- 如果数据库正在被使用,不加
WITH ROLLBACK IMMEDIATE会卡住,执行失败也不报错,只提示“数据库正在使用中” - 执行后查
sys.databases.is_broker_enabled必须为 1;若仍是 0,说明没生效,常见原因是没用master上下文或权限不足 - 改完别忘了
USE YourDB切回目标库,否则后续对象(如队列、服务)可能建在master里
触发器里不能直接 SEND,必须用 BEGIN DIALOG CONVERSATION
触发器运行在主事务内,所有操作必须轻量、快速、可失败。直接 SEND 会因找不到对话句柄报错,而建对话本身也得防异常:
-
BEGIN DIALOG CONVERSATION要指定ENCRYPTION = OFF(跨实例才需证书,单库异步可关) - 务必用
TRY...CATCH包裹建对话和发送逻辑,捕获ERROR_NUMBER() IN (9619, 9627)等常见错误并RETURN,避免阻塞主表 INSERT - 消息体建议用
FOR XML AUTO, ROOT('event'),别手拼 XML 字符串,否则VALIDATION = WELL_FORMED_XML会拒收
接收端要用激活存储过程(ACTIVATION),别轮询
靠应用层定时 RECEIVE 查队列,延迟高、资源浪费、还容易漏消息。SQL Server 原生支持队列自动唤起存储过程:
- 创建队列时指定
ACTIVATION:CREATE QUEUE AuditQueue WITH ACTIVATION (STATUS = ON, PROCEDURE_NAME = dbo.usp_ProcessAuditMessage, MAX_QUEUE_READERS = 2, EXECUTE AS OWNER); -
MAX_QUEUE_READERS设太高反而争抢上下文,1–3 足够;设为 0 就等于禁用激活 - 激活过程里必须用
WAITFOR (RECEIVE ...)+END CONVERSATION配对,漏掉后者会导致对话堆积在sys.conversation_endpoints中 - 过程开头加
IF @@TRANCOUNT > 0 ROLLBACK,防止上游触发器回滚后,激活过程还在处理残留消息
消息积压时 sys.transmission_queue 会暴涨,得盯住它
这不是故障信号,而是 Service Broker 正常工作的表现——只要 transmission_status 字段为空,就说明消息只是暂存,等接收端上线或激活过程空闲就会发走。
真正要干预的是:
- 查
SELECT * FROM sys.transmission_queue WHERE transmission_status LIKE '%not%',出现 “The service does not exist in the current database” 说明远程服务名写错或没创建 - 查
SELECT * FROM sys.dm_broker_queue_monitors,is_active = 0表示队列激活被意外停了,需手动ALTER QUEUE ... WITH ACTIVATION (STATUS = ON) - 别清空
sys.transmission_queue,那是系统表,删了会导致消息永久丢失
最易被忽略的一点:所有 Service Broker 对象(消息类型、契约、队列、服务)都绑定在数据库级,备份恢复后,is_broker_enabled 可能重置为 0,且证书/路由不会自动迁移——跨实例场景下,每次还原都要重新验证三要素是否齐备。










