我正在使用SQL Service Broker。一个连接使用XML消息在队列上发送消息。我有一个WAITFOR (RECEIVE TOP (1) ...), TIMEOUT 5000
的独立连接。这可以在单个Management Studio查询中进行WHILE (1=1)
循环,也可以使用循环reader.NextResult()执行单个ADO.NET SQL命令。
所有这些似乎都被正确配置,因为我最终得到了我期望的每一个结果。
但问题是最近的结果总是被阻止!
假设它已经运行并且没有SEND
s,所以它只是每5秒钟在控制台上打印“无”时间。
现在我从SQL Management Studio查询SEND
。 SEND
命令成功立即完成。在正常超时间隔之前,我立即在控制台中获得“无”。然后在 next 超时间隔,我的“更新”事件出现!
如果我在“无”运行后发出SEND
两条消息,那么我将立即获得“无”,然后获得一个“更新”。同样,在 next 超时间隔,将出现第二个“更新”。
我可以SEND
十条消息并立即获得“无”和九条“更新”。然后我等待五秒钟超时并获得最后的“更新”。
所有SEND
都在同一个对话中,我永远不会结束对话。我不保留。
如果在RECEIVE循环运行时对队列执行脏读,则队列始终为空。如果我停止RECEIVE循环,它会填满。如果我从另一个Management Studio查询窗口接收,则另一条线索是当我停止查询时,始终显示最终输出。这两个事实让我觉得队列正在立即出现,但是有些东西在读者端被锁定(但是什么?)。
起初我认为这只是我之前看到的管理工作室的奇怪行为,PRINT
(?)有时被推迟。但我不希望在ADO.NET中显示相同的行为
也许它与SSB无关,只是WAITFOR或只是多个ResultSet的流媒体。我会调查这些选项,但我希望有人可能会在此期间认识到这一点。
这些症状对您来说是否熟悉?
谢谢!
SEND
之后立即看到sp_lock结果中的任何额外锁定(也没有)对于@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
答案 0 :(得分:1)
不会立即发送打印消息。我经常看到打印调试消息的任意高延迟。我认为SQL Server等待网络数据包已满或者其他类型的缓冲。
如果您只是运行一个无限循环,每秒打印一条小消息,您可能会在N秒后立即获得前N条消息。这可能只是TCP的情况。也许共享内存更快,我不知道。
但我从未见过要延迟的结果集。因此,请执行SELECT 'msg'
尝试“打印”。
对客户端的延迟写入问题众所周知:
另一方面,代码中的所有副作用(写入表格或其他DML)都会立即发生。只有客户端应用会收到延迟的PRINT
条消息。这种延迟根本不会影响您的生产应用,因为所有有用的副作用都会立即发生。
简而言之,要么忽略问题,要么使用RAISERROR('Message', 0, 0) WITH NOWAIT
。仅当严重性大于10时才会抛出异常。
答案 1 :(得分:1)
我相信RAISERROR(...)WITH NOWAIT应该刷新缓冲区,但我已经玩了很长时间了。