Service Broker队列批量收消息仅得一条,求同会话组实现示例
问题:Service Broker队列接收消息仅返回1条,同会话组处理方案
我用以下代码从MyDemoQueue接收消息:
WAITFOR( RECEIVE TOP (100) message_type_name, CAST(message_body AS XML), conversation_handle FROM MyDemoQueue INTO @ReceiveTable ), TIMEOUT 10000;
队列中明明有10条消息,但每次只能获取1条。查资料后得知这和**会话组(conversation group)**有关:RECEIVE语句只会返回同一会话组的消息,因此需要将消息放入同一个会话组。
All messages that are returned by a RECEIVE statement belong the same conversation group
我找不到具体的实现代码示例,仅能看到理论内容,官方文档中也无相关说明,不清楚该在发送端还是接收端处理。
我的消息发送代码如下(会在不同位置/批次多次执行):
DECLARE @Handle UNIQUEIDENTIFIER; DECLARE @MessageBody XML = '<test>hello</test>' BEGIN DIALOG CONVERSATION @Handle FROM SERVICE [SourceService] TO SERVICE 'TargetService' ON CONTRACT [TestContract] WITH ENCRYPTION = OFF; SEND ON CONVERSATION @Handle MESSAGE TYPE [TestMessage](@MessageBody);
另外,执行以下查询可返回多条记录:
SELECT CONVERT(NVARCHAR(MAX), message_body) AS Message FROM MyDemoQueue
解决方案
要让多条消息归属同一个会话组,需在发送端复用同一个对话句柄(conversation_handle),而非每次发送都新建对话。因为每新建一个对话会自动分配到不同的会话组,多次执行原发送代码会生成多个会话组,导致RECEIVE每次仅能获取单个组的消息。
修改后的发送代码
-- 先检查是否已有可用的对话句柄(可持久化到表中,或用全局变量,依场景选择) DECLARE @Handle UNIQUEIDENTIFIER; -- 示例:从存储对话的表中获取已存在的有效对话句柄,无则新建 SELECT @Handle = conversation_handle FROM SavedConversations WHERE from_service = 'SourceService' AND to_service = 'TargetService' AND is_closed = 0; IF @Handle IS NULL BEGIN BEGIN DIALOG CONVERSATION @Handle FROM SERVICE [SourceService] TO SERVICE 'TargetService' ON CONTRACT [TestContract] WITH ENCRYPTION = OFF; -- 将对话句柄保存到表中,供后续发送复用 INSERT INTO SavedConversations (conversation_handle, from_service, to_service, is_closed) VALUES (@Handle, 'SourceService', 'TargetService', 0); END -- 使用同一个对话句柄发送消息 DECLARE @MessageBody XML = '<test>hello</test>' SEND ON CONVERSATION @Handle MESSAGE TYPE [TestMessage](@MessageBody);
补充说明
- 会话组是Service Broker关联相关对话的机制,同一个对话的所有消息都属于同一个会话组,复用对话句柄即可让所有消息进入同组,
RECEIVE就能一次性取出同组多条消息。 - 注意对话生命周期:若对话被关闭(比如收到
END CONVERSATION指令),需重新创建对话并更新保存的句柄。 - 若需批量处理不同会话组的消息,可循环执行
RECEIVE语句,直至队列无消息:
DECLARE @ReceiveTable TABLE ( message_type_name NVARCHAR(256), message_body XML, conversation_handle UNIQUEIDENTIFIER ); WHILE 1 = 1 BEGIN WAITFOR( RECEIVE TOP (100) message_type_name, CAST(message_body AS XML), conversation_handle FROM MyDemoQueue INTO @ReceiveTable ), TIMEOUT 1000; -- 处理@ReceiveTable中的消息 IF @@ROWCOUNT = 0 BREAK; -- 无消息则退出循环 END
内容的提问来源于stack exchange,提问作者Denis Kaminsky
相关产品推荐
相关产品推荐

