多队列读取器场景下事务回滚后毒消息会被其他读取器接收吗
结论
你担心的情况不会出现,核心依据是SQL Server Service Broker内置的**会话组锁(Conversation Group Lock)**机制。
具体逻辑说明
- 当队列读取器A执行
RECEIVE命令获取到某条消息时,会自动对该消息所属的会话组加排他锁,这把锁只有在A的当前事务提交或回滚后才会释放。你明确所有消息都对应独立会话组,所以在A释放锁之前,其他读取器完全无法访问该会话组下的所有消息。 - 当A触发严重错误导致
XACT_STATE() = -1、回滚整个事务时,已经读取的消息会重新回到队列,同时会话组锁被释放。此时你在代码中立即开启新事务,用conversation_handle = @conversation_handle作为过滤条件执行RECEIVE,会第一时间重新抢占该会话组的排他锁,其他队列读取器几乎没有抢到这条消息的可能性。 - 后续你执行
END CONVERSATION @conversation_handle后,该会话会被标记为关闭,对应消息也会被清理,更不可能被其他读取器获取到。
可选优化建议
如果要完全杜绝极端场景下其他读取器抢到消息的可能性,可以在回滚后新开事务时,先执行GET CONVERSATION GROUP命令提前锁定目标会话组,再执行RECEIVE操作,逻辑如下:
IF XACT_STATE() = -1 BEGIN ROLLBACK TRANSACTION DECLARE @conversation_group_id UNIQUEIDENTIFIER BEGIN TRANSACTION; -- 先锁定目标会话组,完全避免其他读取器抢占 GET CONVERSATION GROUP @conversation_group_id FROM [dbo].[my_queue] WHERE conversation_handle = @conversation_handle RECEIVE TOP (1) @message_body = [message_body] FROM [dbo].[my_queue] WHERE conversation_handle = @conversation_handle END
内容的提问来源于stack exchange,提问作者Lucius
相关产品推荐
相关产品推荐

