SQL Server Service Broker
服務體系結構
消息類型 — 定義應用程序間交換的消息的名稱。還可以選擇是否驗證消息。
約定 — 指定給定會話中的消息方向和消息類型。
隊列 — 存儲消息。此存儲機制使服務間可以進行異步通信。Service Broker 隊列還有其他優點,比如自動鎖定同一個會話組中的消息。
服務 — 是可尋址的會話端點。Service Broker 消息從一個服務發送到另一個服務。服務指定一個隊列來保存消息,還指定一些約定,約定指明該服務可作為“目標”。約定向服務提供一組定義完善的消息類型。
處理的先決條件.
USE master;
GO
ALTER DATABASE 目標數據庫
SET ENABLE_BROKER;
GO
-- 如果上面的操作執行后,長時間無反應,有死機的嫌疑,嘗試下面的語句。
ALTER DATABASE 目標數據庫 SET NEW_BROKER WITH ROLLBACK IMMEDIATE;
GO
ALTER DATABASE 目標數據庫 SET ENABLE_BROKER;
GO
USE 目標數據庫;
GO
-------------------- Hello World 的例子 --------------------
-- 創建 SayHelloMessage 消息類型.
-- 該消息類型,不做數據驗證的處理.
CREATE MESSAGE TYPE SayHelloMessage
VALIDATION = None;
GO
-- 創建 約定 SayHelloContract
-- 定義了,發送/接收方.
-- 都是用這個消息類型.
CREATE CONTRACT SayHelloContract (
SayHelloMessage SENT BY ANY
);
GO
-- 創建發送/接收隊列
CREATE QUEUE SayHelloSendQueue;
CREATE QUEUE SayHelloReceiveQueue;
GO
-- 創建發起方服務 SayHelloSendService
-- 該服務使用 SayHelloSendQueue 隊列
-- 由於未指定約定名稱,因而其他服務不可將此服務用作目標服務。
CREATE SERVICE SayHelloSendService
ON QUEUE SayHelloSendQueue;
GO
-- 創建目標服務 SayHelloReceiveService
-- 該服務使用 SayHelloReceiveQueue 隊列
-- 使用 SayHelloContract 約定
CREATE SERVICE SayHelloReceiveService
ON QUEUE SayHelloReceiveQueue
([SayHelloContract]);
GO
-- 測試發送.
BEGIN
-- 定義發送的句柄.
DECLARE @InitDlgHandle UNIQUEIDENTIFIER;
-- 定義變量.
DECLARE @MyMessage NVARCHAR(100);
-- 設置發送消息的內容.
SET @MyMessage = N'Hello World!'
-- 開始事務處理.
BEGIN TRANSACTION;
-- 定義消息發送處理.
BEGIN DIALOG @InitDlgHandle
FROM SERVICE -- 定義發送服務.
SayHelloSendService
TO SERVICE -- 定義接收服務.
N'SayHelloReceiveService'
ON CONTRACT -- 定義使用的約定
SayHelloContract
WITH -- 不加密.
ENCRYPTION = OFF;
-- 發送消息.
SEND ON CONVERSATION @InitDlgHandle
MESSAGE TYPE
[SayHelloMessage]
( @MyMessage );
-- 輸出接收到的消息.
PRINT '我發送了:' + @MyMessage;
-- 提交事務.
COMMIT TRANSACTION;
END
GO
-- 測試接收,處理,並反饋.
BEGIN
-- 接收句柄.
DECLARE @RecvReqDlgHandle UNIQUEIDENTIFIER;
-- 接收到的數據.
DECLARE @RecvReqMsg NVARCHAR(100);
-- 接收到的數據類型名稱.
DECLARE @RecvReqMsgName sysname;
-- 開始事務處理.
BEGIN TRANSACTION;
-- 嘗試從 SayHelloReceiveQueue 隊列 接收消息.
WAITFOR
( RECEIVE TOP(1)
@RecvReqDlgHandle = conversation_handle,
@RecvReqMsg = message_body,
@RecvReqMsgName = message_type_name
FROM SayHelloReceiveQueue
), TIMEOUT 1000;
-- 如果接收到的消息類型名為 SayHelloMessage
-- 那么進行處理.
IF @RecvReqMsgName = N'SayHelloMessage'
BEGIN
-- 定義准備用於返回的消息.
DECLARE @ReplyMsg NVARCHAR(100);
-- 簡單設置.
SELECT @ReplyMsg = '~' + @RecvReqMsg + '~';
-- 調試輸出.
PRINT '我接收到:' + @RecvReqMsg + "; 我將反饋:" + @ReplyMsg;
-- 發送反饋消息.
SEND ON CONVERSATION @RecvReqDlgHandle
MESSAGE TYPE
[SayHelloMessage]
(@ReplyMsg);
END CONVERSATION @RecvReqDlgHandle;
END;
-- 提交事務.
COMMIT TRANSACTION;
END
GO
-- 測試獲取處理結果.
BEGIN
DECLARE @RecvReplyMsg NVARCHAR(100);
DECLARE @RecvReplyDlgHandle UNIQUEIDENTIFIER;
-- 開始事務處理.
BEGIN TRANSACTION;
-- 嘗試從 SayHelloReceiveQueue 隊列 接收消息.
WAITFOR
( RECEIVE TOP(1)
@RecvReplyDlgHandle = conversation_handle,
@RecvReplyMsg = message_body
FROM SayHelloSendQueue
), TIMEOUT 1000;
END CONVERSATION @RecvReplyDlgHandle;
-- 輸出接收到的消息.
PRINT '我接收到反饋:' + @RecvReplyMsg;
-- 提交事務.
COMMIT TRANSACTION;
END
GO
-------------------- Hello World 內部激活的例子 --------------------
-- 專門用於處理消息的存儲過程.
CREATE PROCEDURE SayHelloQueueProc
AS
BEGIN
-- 接收句柄.
DECLARE @RecvReqDlgHandle UNIQUEIDENTIFIER;
-- 接收到的數據.
DECLARE @RecvReqMsg NVARCHAR(100);
-- 接收到的數據類型名稱.
DECLARE @RecvReqMsgName sysname;
-- 循環處理.
WHILE (1=1)
BEGIN
-- 開始事務處理.
BEGIN TRANSACTION;
-- 嘗試從 SayHelloReceiveQueue 隊列 接收消息.
WAITFOR
( RECEIVE TOP(1)
@RecvReqDlgHandle = conversation_handle,
@RecvReqMsg = message_body,
@RecvReqMsgName = message_type_name
FROM SayHelloReceiveQueue
), TIMEOUT 5000;
-- 判斷有沒有獲取到消息.
IF (@@ROWCOUNT = 0)
BEGIN
-- 如果沒有接收到消息
-- 回滾事務.
ROLLBACK TRANSACTION;
-- 跳出循環.
BREAK;
END
-- 如果接收到的消息類型名為 SayHelloMessage
-- 那么進行處理.
IF @RecvReqMsgName = N'SayHelloMessage'
BEGIN
-- 定義准備用於返回的消息.
DECLARE @ReplyMsg NVARCHAR(100);
-- 簡單設置.
SELECT @ReplyMsg = '~' + @RecvReqMsg + '~';
-- 調試輸出.
PRINT '我接收到:' + @RecvReqMsg + "; 我將反饋:" + @ReplyMsg;
-- 發送反饋消息.
SEND ON CONVERSATION @RecvReqDlgHandle
MESSAGE TYPE
[SayHelloMessage]
(@ReplyMsg);
END CONVERSATION @RecvReqDlgHandle;
END;
-- 提交事務.
COMMIT TRANSACTION;
END
END
GO
-- 更改目標隊列以指定內部激活
-- 也就是當有消息發送到 SayHelloReceiveQueue 隊列的時候.
-- 自動調用 SayHelloQueueProc 存儲過程 進行處理.
ALTER QUEUE SayHelloReceiveQueue
WITH ACTIVATION
( STATUS = ON,
PROCEDURE_NAME = SayHelloQueueProc,
MAX_QUEUE_READERS = 10,
EXECUTE AS SELF
);
GO
-- 由於消息已經處於自動處理的方式。
-- 測試發送 並 接收.
BEGIN
-- 定義發送的句柄.
DECLARE @InitDlgHandle UNIQUEIDENTIFIER;
-- 定義變量.
DECLARE @MyMessage NVARCHAR(100);
-- 設置發送消息的內容.
SET @MyMessage = N'Hello World!'
-- 開始事務處理.
BEGIN TRANSACTION;
-- 定義消息發送處理.
BEGIN DIALOG @InitDlgHandle
FROM SERVICE -- 定義發送服務.
SayHelloSendService
TO SERVICE -- 定義接收服務.
N'SayHelloReceiveService'
ON CONTRACT -- 定義使用的約定
SayHelloContract
WITH -- 不加密.
ENCRYPTION = OFF;
-- 發送消息.
SEND ON CONVERSATION @InitDlgHandle
MESSAGE TYPE
[SayHelloMessage]
( @MyMessage );
-- 輸出接收到的消息.
PRINT '我發送了:' + @MyMessage;
-- 提交事務.
COMMIT TRANSACTION;
-- 等待 5 秒.
WAITFOR DELAY '00:00:05';
DECLARE @RecvReplyMsg NVARCHAR(100);
DECLARE @RecvReplyDlgHandle UNIQUEIDENTIFIER;
-- 開始事務處理.
BEGIN TRANSACTION;
-- 嘗試從 SayHelloReceiveQueue 隊列 接收消息.
WAITFOR
( RECEIVE TOP(1)
@RecvReplyDlgHandle = conversation_handle,
@RecvReplyMsg = message_body
FROM SayHelloSendQueue
), TIMEOUT 1000;
END CONVERSATION @RecvReplyDlgHandle;
-- 輸出接收到的消息.
PRINT '我接收到反饋:' + @RecvReplyMsg;
-- 提交事務.
COMMIT TRANSACTION;
END
GO
我發送了:Hello World!
(1 行受影響)
我接收到反饋:~Hello World!~