构建使用异步通信的分布式应用程序的基础知识之一可以表示为不要主动等待任何事件!这样,基于 SQL 服务代理的自然解决方案是使用到达队列的消息激活存储过程。
官方Microsoft教程中的第 2 课:创建内部激活过程演示如何将存储过程绑定到消息队列。它还建议了如何实现 sp
。(我是SQL的新手。但是难道不应该在CREATE PROCEDURE... AS
之后再多一个BEGIN
,在GO
之前再多一个END
吗?
我理解得很明白吗?请参阅代码下方的问题...
CREATE PROCEDURE TargetActivProc
AS
DECLARE @RecvReqDlgHandle UNIQUEIDENTIFIER;
DECLARE @RecvReqMsg NVARCHAR(100);
DECLARE @RecvReqMsgName sysname;
WHILE (1=1)
BEGIN
BEGIN TRANSACTION;
WAITFOR
( RECEIVE TOP(1)
@RecvReqDlgHandle = conversation_handle,
@RecvReqMsg = message_body,
@RecvReqMsgName = message_type_name
FROM TargetQueueIntAct
), TIMEOUT 5000;
IF (@@ROWCOUNT = 0)
BEGIN
ROLLBACK TRANSACTION;
BREAK;
END
IF @RecvReqMsgName =
N'//AWDB/InternalAct/RequestMessage'
BEGIN
DECLARE @ReplyMsg NVARCHAR(100);
SELECT @ReplyMsg =
N'<ReplyMsg>Message for Initiator service.</ReplyMsg>';
SEND ON CONVERSATION @RecvReqDlgHandle
MESSAGE TYPE
[//AWDB/InternalAct/ReplyMessage]
(@ReplyMsg);
END
ELSE IF @RecvReqMsgName =
N'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog'
BEGIN
END CONVERSATION @RecvReqDlgHandle;
END
ELSE IF @RecvReqMsgName =
N'http://schemas.microsoft.com/SQL/ServiceBroker/Error'
BEGIN
END CONVERSATION @RecvReqDlgHandle;
END
COMMIT TRANSACTION;
END
GO
当消息到达时,将调用该过程,并进入"无限"循环。实际上,循环不是无限的,因为没有数据到达时ROLLBACK
之后(TIMEOUT
之后)的BREAK
。
如果数据到达,则跳过BREAK
。如果预期的消息到达,则会发回回复。如果收到...EndDialog
或...Error
消息,则执行END CONVERSATION
。这里还可以观察到其他类型的信息吗?
当某些消息到达(并被处理)时,事务被提交。
但为什么现在循环?是否打算处理由于过去通信线路断开而卡在队列中的其他消息?还是因为一次收到更多消息并且无法如此快速地处理?
当另一条消息排队,并且存储过程仍在运行时会发生什么情况。是否为其处理分配了另一个工作进程?是否可以并行启动另一个存储过程?如果是,那为什么要循环?
谢谢你的帮助,彼得
内部激活不像触发器。具体而言,不会为到达的每条消息启动激活的过程。相反,该过程在有内容要处理时启动,并且应该在 SSB 基础结构监视进度时连续(在循环中)取消消息排队,并在必要时启动第二个过程来提供帮助,直到指定的最大值。请参阅了解队列监视器。
在激活的过程中有一个循环并不是严格要求的,即使没有循环,事情也应该工作正常。循环在非常繁忙的环境中应该表现得更好。另请参阅此旧的 MSDN 讨论。