在 Sql 服务器中使用服务代理进行异步过程调用
Async procedure call using service broker in Sql Server
我每天都有一个备份程序(生产)运行,生成的备份会定期用于刷新较低的环境。我正在构建一个自动化解决方案来将 .bak 文件下载到较低的环境(不同的服务器)。我不愿意在备份中使用 MIRROR TO 选项,因为如果镜像到 .我在这里想使用服务代理并在备份过程结束时异步触发从生产环境到较低环境的文件复制。我在理解服务代理、消息类型、服务、队列和契约方面付出了很多努力。一切都很好,直到这里。现在我只想了解如何使用服务代理在备份结束时使用一些自定义逻辑触发文件复制过程。我玩过以下脚本来了解服务代理。有人好心地指导我如何从中构建解决方案。
------------------------------------------------------------SETUP--------------------------------------------
CREATE MESSAGE TYPE [//SBTest/SBSample/RequestMessage] VALIDATION=WELL_FORMED_XML;
CREATE MESSAGE TYPE [//SBTest/SBSample/ReplyMessage] VALIDATION=WELL_FORMED_XML;
-------------------------------------------------------------------------------------------------------------
CREATE CONTRACT [//SBTest/SBSample/SBContract]
(
[//SBTest/SBSample/RequestMessage] SENT BY INITIATOR ,
[//SBTest/SBSample/ReplyMessage] SENT BY TARGET
);
-------------------------------------------------------------------------------------------------------------
CREATE QUEUE SBInitiatorQueue;
CREATE QUEUE SBTargetQueue;
-------------------------------------------------------------------------------------------------------------
CREATE SERVICE [//SBTest/SBSample/SBInitiatorService] ON QUEUE SBInitiatorQueue;
CREATE SERVICE [//SBTest/SBSample/SBTargetService] ON QUEUE SBTargetQueue ([//SBTest/SBSample/SBContract]);
-------------------------------------------------------------------------------------------------------------
-------------------------------------------------------INITIATE QUE-----------------------------------------
DECLARE @InitDlgHandle UNIQUEIDENTIFIER
DECLARE @RequestMessage VARCHAR(1000)
BEGIN TRAN
--Determine the Initiator Service, Target Service and the Contract
BEGIN DIALOG @InitDlgHandle
FROM SERVICE [//SBTest/SBSample/SBInitiatorService] TO SERVICE'//SBTest/SBSample/SBTargetService'
ON CONTRACT
[//SBTest/SBSample/SBContract]
WITH ENCRYPTION=OFF;
--Prepare the Message
SELECT @RequestMessage = N'HAHA';
--Send the Message
SEND ON CONVERSATION @InitDlgHandle
MESSAGE TYPE
[//SBTest/SBSample/RequestMessage]
(@RequestMessage);
SELECT @RequestMessage AS SentRequestMessage;
COMMIT TRAN
---------------------------------------------------------------------------------------------------------------
-------------------------------------------------------READ QUE-------------------------------------------------
\DECLARE @TargetDlgHandle UNIQUEIDENTIFIER
DECLARE @ReplyMessage VARCHAR(1000)
DECLARE @ReplyMessageName Sysname
BEGIN TRAN;
--Receive message from Initiator
RECEIVE TOP(1)
@TargetDlgHandle=Conversation_Handle, @ReplyMessage=Message_Body, @ReplyMessageName=Message_Type_Name
FROM SBTargetQueue;
SELECT @ReplyMessage AS ReceivedRequestMessage;
-- Confirm and Send a reply
IF @ReplyMessageName=N'HAHA'
BEGIN
DECLARE @RplyMsg VARCHAR(1000)
SELECT @RplyMsg =N'HI';
SEND ON CONVERSATION @TargetDlgHandle
MESSAGE TYPE
[//SBTest/SBSample/ReplyMessage]
(@RplyMsg);
END CONVERSATION @TargetDlgHandle;
END
SELECT @RplyMsg AS SentReplyMessage;
COMMIT TRAN;
-------------------------------------------------------------------------------------------------------------------
使用 "Internal Activation" 触发。您需要创建一个存储过程,该过程将在消息进入队列、从队列中读取然后执行工作时触发。
改编自 link:
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'//SBTest/SBSample/RequestMessage'
BEGIN
--do work here
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
下一部分是在队列上启用激活
ALTER QUEUE SBTargetQueue
WITH ACTIVATION
( STATUS = ON,
PROCEDURE_NAME = TargetActivProc,
MAX_QUEUE_READERS = 1,
EXECUTE AS SELF
);
该过程将在消息到达队列时激活,并保持激活和循环直到队列为空。
我每天都有一个备份程序(生产)运行,生成的备份会定期用于刷新较低的环境。我正在构建一个自动化解决方案来将 .bak 文件下载到较低的环境(不同的服务器)。我不愿意在备份中使用 MIRROR TO 选项,因为如果镜像到 .我在这里想使用服务代理并在备份过程结束时异步触发从生产环境到较低环境的文件复制。我在理解服务代理、消息类型、服务、队列和契约方面付出了很多努力。一切都很好,直到这里。现在我只想了解如何使用服务代理在备份结束时使用一些自定义逻辑触发文件复制过程。我玩过以下脚本来了解服务代理。有人好心地指导我如何从中构建解决方案。
------------------------------------------------------------SETUP--------------------------------------------
CREATE MESSAGE TYPE [//SBTest/SBSample/RequestMessage] VALIDATION=WELL_FORMED_XML;
CREATE MESSAGE TYPE [//SBTest/SBSample/ReplyMessage] VALIDATION=WELL_FORMED_XML;
-------------------------------------------------------------------------------------------------------------
CREATE CONTRACT [//SBTest/SBSample/SBContract]
(
[//SBTest/SBSample/RequestMessage] SENT BY INITIATOR ,
[//SBTest/SBSample/ReplyMessage] SENT BY TARGET
);
-------------------------------------------------------------------------------------------------------------
CREATE QUEUE SBInitiatorQueue;
CREATE QUEUE SBTargetQueue;
-------------------------------------------------------------------------------------------------------------
CREATE SERVICE [//SBTest/SBSample/SBInitiatorService] ON QUEUE SBInitiatorQueue;
CREATE SERVICE [//SBTest/SBSample/SBTargetService] ON QUEUE SBTargetQueue ([//SBTest/SBSample/SBContract]);
-------------------------------------------------------------------------------------------------------------
-------------------------------------------------------INITIATE QUE-----------------------------------------
DECLARE @InitDlgHandle UNIQUEIDENTIFIER
DECLARE @RequestMessage VARCHAR(1000)
BEGIN TRAN
--Determine the Initiator Service, Target Service and the Contract
BEGIN DIALOG @InitDlgHandle
FROM SERVICE [//SBTest/SBSample/SBInitiatorService] TO SERVICE'//SBTest/SBSample/SBTargetService'
ON CONTRACT
[//SBTest/SBSample/SBContract]
WITH ENCRYPTION=OFF;
--Prepare the Message
SELECT @RequestMessage = N'HAHA';
--Send the Message
SEND ON CONVERSATION @InitDlgHandle
MESSAGE TYPE
[//SBTest/SBSample/RequestMessage]
(@RequestMessage);
SELECT @RequestMessage AS SentRequestMessage;
COMMIT TRAN
---------------------------------------------------------------------------------------------------------------
-------------------------------------------------------READ QUE-------------------------------------------------
\DECLARE @TargetDlgHandle UNIQUEIDENTIFIER
DECLARE @ReplyMessage VARCHAR(1000)
DECLARE @ReplyMessageName Sysname
BEGIN TRAN;
--Receive message from Initiator
RECEIVE TOP(1)
@TargetDlgHandle=Conversation_Handle, @ReplyMessage=Message_Body, @ReplyMessageName=Message_Type_Name
FROM SBTargetQueue;
SELECT @ReplyMessage AS ReceivedRequestMessage;
-- Confirm and Send a reply
IF @ReplyMessageName=N'HAHA'
BEGIN
DECLARE @RplyMsg VARCHAR(1000)
SELECT @RplyMsg =N'HI';
SEND ON CONVERSATION @TargetDlgHandle
MESSAGE TYPE
[//SBTest/SBSample/ReplyMessage]
(@RplyMsg);
END CONVERSATION @TargetDlgHandle;
END
SELECT @RplyMsg AS SentReplyMessage;
COMMIT TRAN;
-------------------------------------------------------------------------------------------------------------------
使用 "Internal Activation" 触发。您需要创建一个存储过程,该过程将在消息进入队列、从队列中读取然后执行工作时触发。 改编自 link:
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'//SBTest/SBSample/RequestMessage'
BEGIN
--do work here
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
下一部分是在队列上启用激活
ALTER QUEUE SBTargetQueue
WITH ACTIVATION
( STATUS = ON,
PROCEDURE_NAME = TargetActivProc,
MAX_QUEUE_READERS = 1,
EXECUTE AS SELF
);
该过程将在消息到达队列时激活,并保持激活和循环直到队列为空。