【发布时间】:2012-08-13 23:04:22
【问题描述】:
构建使用异步通信的分布式应用程序的基础之一可以表示为不要主动等待任何事件!这样,基于SQL Service Broker的自然解决方案是使用通过到达队列的消息激活存储过程。
微软官方教程中的Lesson 2: Creating an Internal Activation Procedure 展示了如何将存储过程绑定到消息队列。它还提出了应该如何实现 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之后的BREAK在没有数据到达时(TIMEOUT之后)。
如果数据到达,则跳过BREAK。如果预期的消息到达,则将回复发回。如果收到...EndDialog 或...Error 消息,则执行END CONVERSATION。这里还可以观察到其他类型的消息吗?
当一些消息到达(并被处理)时,事务被提交。
但是为什么现在循环呢?是否打算处理过去因为通信线路中断而卡在队列中的其他消息?还是因为一次性收到的消息较多,无法这么快处理?
当另一条消息排队并且存储过程仍在运行时会发生什么。是否为其处理分配了另一个工作流程?可以并行启动另一个存储过程吗?如果是,那为什么是循环?
谢谢你的帮助,彼得
【问题讨论】: