我正在使用 SQL 服务代理。一个连接使用 XML 消息在队列上发送消息。我有一个独立的连接,即WAITFOR (RECEIVE TOP (1) ...), TIMEOUT 5000
. 这会在WHILE (1=1)
单个 Management Studio 查询或使用循环 reader.NextResult() 的单个 ADO.NET SQL 命令执行中循环。
所有这一切似乎都已正确配置,因为我最终得到了我期望的每一个结果。
但问题是最近的结果总是被阻止!
假设它一直在运行并且没有SEND
s,所以它只是保持超时,每 5 秒在控制台上打印一次“None”。
那么现在我SEND
从 SQL Management Studio 查询。该SEND
命令立即成功完成。在正常超时间隔之前,我立即在控制台中获得“无” 。然后在下一个超时间隔,我的“更新”事件出现了!
如果我SEND
在一系列“无”之后收到两条消息,那么我会立即收到“无”,然后是一条“更新”。同样,在下一个超时间隔,将出现第二个“更新”。
我可以SEND
发送 10 条消息并立即收到一条“无”和九条“更新”。然后我等待五秒超时并获得最终的“更新”。
所有SEND
s 都在同一个对话中,我从不结束对话。我不保留。
如果我在 RECEIVE 循环运行时对队列进行脏读,则队列始终为空。如果我停止接收循环,它会填满。如果我从另一个 Management Studio 查询窗口收到,则另一个线索是,当我停止查询时,始终会出现最终输出。这两个事实使我认为队列正在立即出队,但是阅读器方面正在锁定某些东西(但是什么??)。
起初,我认为这只是 Management Studio 的一种奇怪行为,我以前见过PRINT
(?)有时会延迟。但我不希望在 ADO.NET 中出现同样的行为
也许它与 SSB 无关,只是 WAITFOR 或只是多个 ResultSet 的流式传输。我会调查这些选项,但我希望有人能在此期间认识到这一点。
这些症状你熟悉吗?
谢谢!
- 是否有某种方法可以在下一个阻塞操作之前将结果刷新到连接?结果/结果集交付是否延迟?
- 我没有在 sp_lock 结果之后立即看到任何额外的锁定
SEND
(或者其他情况)
对于@Rikalous,这里是 ADO.NET
using (var cmd = connection.CreateCommand())
{
cmd.CommandTimeout = 0;
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.CommandText = "upWaitForReceive";
using (var reader = cmd.ExecuteReader())
{
do
{
while (reader.Read()) // Individual messages received
{
string eventType = reader["EventType"] as string;
// do something with the message
}
} while (reader.NextResult()); // next batch
}
}
sql循环是:
SELECT 'Initialized' AS EventType
WHILE (1=1) BEGIN
;DECLARE
@ConversationHandle UNIQUEIDENTIFIER,
@MessageTypeName SYSNAME,
@MessageBody XML
;WAITFOR(
RECEIVE TOP (1) @ConversationHandle = conversation_handle, @MessageTypeName = message_type_name, @MessageBody = message_body
FROM [dbo].[{0}_EventsQueue]
), TIMEOUT 5000
IF (@@ROWCOUNT = 0) BEGIN
SELECT 'None' AS EventType; -- Allow the blocking call to spin anyway
CONTINUE;
END
IF (@MessageTypeName = ...) BEGIN
SELECT ...
END ELSE IF (@MessageTypeName = 'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog') BEGIN
END CONVERSATION @ConversationHandle
SELECT @Message = 'Conversation Terminated' -- Not Expected
RAISERROR (@Message, 11, 1)
RETURN
END
END
;END CONVERSATION @ConversationHandle -- This will never be reached. But if it were, this is what should be done