一个sql server service broker例子

-----------------------------------
USE master
GO
--------------------------------------------------
-- Create demo database section
-------------------------------------------------- IF EXISTS (SELECT name FROM sys.databases WHERE name = 'SsbDemoDb')
DROP DATABASE [SsbDemoDb]; CREATE DATABASE [SsbDemoDb]
GO USE [SsbDemoDb];
GO --------------------------------------------------
-- Dialog pool section
-------------------------------------------------- --------------------------------------------------
-- The dialog pool table.
-- Obtain a conversation handle using from service, to service, and contract.
-- Also indicates age and usage of dialog for auditing purposes.
-------------------------------------------------- IF EXISTS (SELECT name FROM sys.tables WHERE name = 'DialogPool')
DROP TABLE [DialogPool]
GO CREATE TABLE [DialogPool] (
FromService SYSNAME NOT NULL,
ToService SYSNAME NOT NULL,
OnContract SYSNAME NOT NULL,
Handle UNIQUEIDENTIFIER NOT NULL,
OwnerSPID INT NOT NULL,
CreationTime DATETIME NOT NULL,
SendCount BIGINT NOT NULL,
UNIQUE (Handle));
GO --------------------------------------------------
-- Get dialog procedure.
-- Reuse a free dialog in the pool or create a new one in case
-- no free dialogs exist.
-- Input is from service, to service, and contract.
-- Output is dialog handle and count of message previously sent on dialog.
-------------------------------------------------- IF EXISTS (SELECT name FROM sys.procedures WHERE name = 'usp_get_dialog')
DROP PROC usp_get_dialog
GO CREATE PROCEDURE [usp_get_dialog] (
@fromService SYSNAME,
@toService SYSNAME,
@onContract SYSNAME,
@dialogHandle UNIQUEIDENTIFIER OUTPUT,
@sendCount BIGINT OUTPUT)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @dialog TABLE
(
FromService SYSNAME NOT NULL,
ToService SYSNAME NOT NULL,
OnContract SYSNAME NOT NULL,
Handle UNIQUEIDENTIFIER NOT NULL,
OwnerSPID INT NOT NULL,
CreationTime DATETIME NOT NULL,
SendCount BIGINT NOT NULL
); -- Try to claim an unused dialog in [DialogPool]
-- READPAST option avoids blocking on locked dialogs.
BEGIN TRANSACTION;
DELETE @dialog;
UPDATE TOP(1) [DialogPool] WITH(READPAST)
SET OwnerSPID = @@SPID
OUTPUT INSERTED.* INTO @dialog
WHERE FromService = @fromService
AND ToService = @toService
AND OnContract = @OnContract
AND OwnerSPID = -1;
IF @@ROWCOUNT > 0
BEGIN
SET @dialogHandle = (SELECT Handle FROM @dialog);
SET @sendCount = (SELECT SendCount FROM @dialog);
END
ELSE
BEGIN
-- No free dialogs: need to create a new one
BEGIN DIALOG CONVERSATION @dialogHandle
FROM SERVICE @fromService
TO SERVICE @toService
ON CONTRACT @onContract
WITH ENCRYPTION = OFF;
INSERT INTO [DialogPool]
(FromService, ToService, OnContract, Handle, OwnerSPID,
CreationTime, SendCount)
VALUES
(@fromService, @toService, @onContract, @dialogHandle, @@SPID,
GETDATE(), 0);
SET @sendCount = 0;
END
COMMIT
END;
GO --------------------------------------------------
-- Free dialog procedure.
-- Return the dialog to the pool.
-- Inputs are dialog handle and updated send count.
-------------------------------------------------- IF EXISTS (SELECT name FROM sys.procedures WHERE name = 'usp_free_dialog')
DROP PROC usp_free_dialog
GO CREATE PROCEDURE [usp_free_dialog] (
@dialogHandle UNIQUEIDENTIFIER,
@sendCount BIGINT)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @rowcount INT;
DECLARE @string VARCHAR(50);
BEGIN TRANSACTION;
-- Release dialog by setting OwnerSPID to -1.
UPDATE [DialogPool] SET OwnerSPID = -1, SendCount = @sendCount WHERE Handle = @dialogHandle;
SELECT @rowcount = @@ROWCOUNT;
IF @rowcount = 0
BEGIN
SET @string = (SELECT CAST( @dialogHandle AS VARCHAR(50)));
RAISERROR('usp_free_dialog: dialog %s not found in dialog pool', 16, 1, @string) WITH LOG;
END
ELSE IF @rowcount > 1
BEGIN
SET @string = (SELECT CAST( @dialogHandle AS VARCHAR(50)));
RAISERROR('usp_free_dialog: duplicate dialog %s found in dialog pool', 16, 1, @string) WITH LOG;
END
COMMIT
END; GO --------------------------------------------------
-- Delete dialog procedure.
-- Delete the dialog from the pool. This does not end the dialog.
-- Input is dialog handle.
-------------------------------------------------- IF EXISTS (SELECT name FROM sys.procedures WHERE name = 'usp_delete_dialog')
DROP PROC usp_delete_dialog
GO CREATE PROCEDURE [usp_delete_dialog] (
@dialogHandle UNIQUEIDENTIFIER)
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRANSACTION;
DELETE [DialogPool] WHERE Handle = @dialogHandle;
COMMIT
END;
GO --------------------------------------------------
-- Application setup section.
-------------------------------------------------- --------------------------------------------------
-- Send messages from initiator to target.
-- Initiator uses dialogs from the dialog pool.
-- Initiator also retires dialogs based on application criteria,
-- which results in recycling dialogs in the pool.
--------------------------------------------------
-- This table stores the messages on the target side IF EXISTS (SELECT name FROM sys.tables WHERE name = 'MsgTable')
DROP TABLE MsgTable
GO CREATE TABLE MsgTable ( message_type SYSNAME, message_body NVARCHAR(4000))
GO -- Activated store proc for the initiator to receive messages. CREATE PROCEDURE initiator_queue_activated_procedure
AS
BEGIN
DECLARE @handle UNIQUEIDENTIFIER;
DECLARE @message_type SYSNAME;
BEGIN TRANSACTION;
WAITFOR (
RECEIVE TOP(1) @handle = [conversation_handle],
@message_type = [message_type_name]
FROM [SsbInitiatorQueue]), TIMEOUT 5000;
IF @@ROWCOUNT = 1
BEGIN
-- Expect target response to EndOfStream message.
IF @message_type = 'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog'
BEGIN
END CONVERSATION @handle;
END
END
COMMIT
END; GO -- Activated store proc for the target to receive messages. CREATE PROCEDURE target_queue_activated_procedure
AS
BEGIN
-- Variable table for received messages.
DECLARE @receive_table TABLE(
queuing_order BIGINT,
conversation_handle UNIQUEIDENTIFIER,
message_type_name SYSNAME,
message_body VARCHAR(MAX)); -- Cursor for received message table.
DECLARE message_cursor CURSOR LOCAL FORWARD_ONLY READ_ONLY
FOR SELECT
conversation_handle,
message_type_name,
message_body
FROM @receive_table ORDER BY queuing_order; DECLARE @conversation_handle UNIQUEIDENTIFIER;
DECLARE @message_type SYSNAME;
DECLARE @message_body VARCHAR(4000); -- Error variables.
DECLARE @error_number INT;
DECLARE @error_message VARCHAR(4000);
DECLARE @error_severity INT;
DECLARE @error_state INT;
DECLARE @error_procedure SYSNAME;
DECLARE @error_line INT;
DECLARE @error_dialog VARCHAR(50); BEGIN TRY
WHILE (1 = 1)
BEGIN
BEGIN TRANSACTION;
-- Receive all available messages into the table.
-- Wait 5 seconds for messages.
WAITFOR (
RECEIVE
[queuing_order],
[conversation_handle],
[message_type_name],
CAST([message_body] AS VARCHAR(4000))
FROM [SsbTargetQueue]
INTO @receive_table
), TIMEOUT 5000; IF @@ROWCOUNT = 0
BEGIN
COMMIT;
BREAK;
END
ELSE
BEGIN
OPEN message_cursor;
WHILE (1=1)
BEGIN
FETCH NEXT FROM message_cursor
INTO @conversation_handle,
@message_type,
@message_body;
IF (@@FETCH_STATUS != 0) BREAK;
-- Process a message.
-- If an exception occurs, catch and attempt to recover.
BEGIN TRY
IF @message_type = 'SsbMsgType'
BEGIN
-- process the msg. Here we will just insert it into a table
INSERT INTO MsgTable values(@message_type, @message_body);
END
ELSE IF @message_type = 'EndOfStream'
BEGIN
-- initiator is signaling end of message stream: end the dialog
END CONVERSATION @conversation_handle;
END
ELSE IF @message_type = 'http://schemas.microsoft.com/SQL/ServiceBroker/Error'
BEGIN
-- If the message_type indicates that the message is an error,
-- raise the error and end the conversation.
WITH XMLNAMESPACES ('http://schemas.microsoft.com/SQL/ServiceBroker/Error' AS ssb)
SELECT
@error_number = CAST(@message_body AS XML).value('(//ssb:Error/ssb:Code)[1]', 'INT'),
@error_message = CAST(@message_body AS XML).value('(//ssb:Error/ssb:Description)[1]', 'VARCHAR(4000)');
SET @error_dialog = CAST(@conversation_handle AS VARCHAR(50));
RAISERROR('Error in dialog %s: %s (%i)', 16, 1, @error_dialog, @error_message, @error_number);
END CONVERSATION @conversation_handle;
END
END TRY
BEGIN CATCH
SET @error_number = ERROR_NUMBER();
SET @error_message = ERROR_MESSAGE();
SET @error_severity = ERROR_SEVERITY();
SET @error_state = ERROR_STATE();
SET @error_procedure = ERROR_PROCEDURE();
SET @error_line = ERROR_LINE(); IF XACT_STATE() = -1
BEGIN
-- The transaction is doomed. Only rollback possible.
-- This could disable the queue if done 5 times consecutively!
ROLLBACK TRANSACTION; -- Record the error.
BEGIN TRANSACTION;
INSERT INTO target_processing_errors VALUES(NULL, @error_number, @error_message,
@error_severity, @error_state, @error_procedure, @error_line, 1);
COMMIT; -- For this level of error, it is best to exit the proc
-- and give the queue monitor control.
-- Breaking to the outer catch will accomplish this.
RAISERROR ('Message processing error', 16, 1);
END
ELSE IF XACT_STATE() = 1
BEGIN
-- Record error and continue processing messages.
-- Failing message could also be put aside for later processing here.
-- Otherwise it will be discarded.
INSERT INTO target_processing_errors VALUES(NULL, @error_number, @error_message,
@error_severity, @error_state, @error_procedure, @error_line, 0);
END
END CATCH
END
CLOSE message_cursor;
DELETE @receive_table;
END
COMMIT;
END
END TRY
BEGIN CATCH
-- Process the error and exit the proc to give the queue monitor control
SET @error_number = ERROR_NUMBER();
SET @error_message = ERROR_MESSAGE();
SET @error_severity = ERROR_SEVERITY();
SET @error_state = ERROR_STATE();
SET @error_procedure = ERROR_PROCEDURE();
SET @error_line = ERROR_LINE(); IF XACT_STATE() = -1
BEGIN
-- The transaction is doomed. Only rollback possible.
-- This could disable the queue if done 5 times consecutively!
ROLLBACK TRANSACTION;
-- Record the error.
BEGIN TRANSACTION;
INSERT INTO target_processing_errors VALUES(NULL, @error_number, @error_message,
@error_severity, @error_state, @error_procedure, @error_line, 1);
COMMIT;
END
ELSE IF XACT_STATE() = 1
BEGIN
-- Record error and commit transaction.
-- Here you could also save anything else you want before exiting.
INSERT INTO target_processing_errors VALUES(NULL, @error_number, @error_message,
@error_severity, @error_state, @error_procedure, @error_line, 0);
COMMIT;
END
END CATCH
END;
GO -- Table to store processing errors. IF EXISTS (SELECT name FROM sys.tables WHERE name = 'target_processing_errors')
DROP TABLE target_processing_errors;
GO CREATE TABLE target_processing_errors (error_conversation UNIQUEIDENTIFIER, error_number INT,
error_message VARCHAR(4000), error_severity INT, error_state INT, error_procedure SYSNAME NULL,
error_line INT, doomed_transaction TINYINT)
GO -- Create Initiator and Target side SSB entities
CREATE MESSAGE TYPE SsbMsgType VALIDATION = WELL_FORMED_XML;
CREATE MESSAGE TYPE EndOfStream;
CREATE CONTRACT SsbContract
(
SsbMsgType SENT BY INITIATOR,
EndOfStream SENT BY INITIATOR
); CREATE QUEUE SsbInitiatorQueue
WITH ACTIVATION (
STATUS = ON,
MAX_QUEUE_READERS = 1,
PROCEDURE_NAME = [initiator_queue_activated_procedure],
EXECUTE AS OWNER);
CREATE QUEUE SsbTargetQueue
WITH ACTIVATION (
STATUS = ON,
MAX_QUEUE_READERS = 1,
PROCEDURE_NAME = [target_queue_activated_procedure],
EXECUTE AS OWNER); CREATE SERVICE SsbInitiatorService ON QUEUE SsbInitiatorQueue; CREATE SERVICE SsbTargetService ON QUEUE SsbTargetQueue (SsbContract); GO -- SEND procedure. Uses a dialog from the dialog pool.
-- IF EXISTS (SELECT name FROM sys.procedures WHERE name = 'usp_send')
DROP PROC usp_send
GO
CREATE PROCEDURE [usp_send] (
@fromService SYSNAME,
@toService SYSNAME,
@onContract SYSNAME,
@messageType SYSNAME,
@messageBody NVARCHAR(MAX))
AS
BEGIN
SET NOCOUNT ON;
DECLARE @dialogHandle UNIQUEIDENTIFIER;
DECLARE @sendCount BIGINT;
DECLARE @counter INT;
DECLARE @error INT;
SELECT @counter = 1;
BEGIN TRANSACTION;
-- Will need a loop to retry in case the dialog is
-- in a state that does not allow transmission
--
WHILE (1=1)
BEGIN
-- Claim a dialog from the dialog pool.
-- A new one will be created if none are available.
--
EXEC usp_get_dialog @fromService, @toService, @onContract, @dialogHandle OUTPUT, @sendCount OUTPUT; -- Attempt to SEND on the dialog
--
IF (@messageBody IS NOT NULL)
BEGIN
-- If the @messageBody is not null it must be sent explicitly
SEND ON CONVERSATION @dialogHandle MESSAGE TYPE @messageType (@messageBody);
END
ELSE
BEGIN
-- Messages with no body must *not* specify the body,
-- cannot send a NULL value argument
SEND ON CONVERSATION @dialogHandle MESSAGE TYPE @messageType;
END SELECT @error = @@ERROR;
IF @error = 0
BEGIN
-- Successful send, increment count and exit the loop
--
SET @sendCount = @sendCount + 1;
BREAK;
END SELECT @counter = @counter+1;
IF @counter > 10
BEGIN
-- We failed 10 times in a row, something must be broken
--
RAISERROR('Failed to SEND on a conversation for more than 10 times. Error %i.', 16, 1, @error) WITH LOG;
BREAK;
END -- Delete the associated dialog from the table and try again
--
EXEC usp_delete_dialog @dialogHandle;
SELECT @dialogHandle = NULL;
END -- “Criterion” for dialog pool removal is send count > 1000.
-- Modify to suit application.
-- When deleting also inform the target to end the dialog.
IF @sendCount > 1000
BEGIN
EXEC usp_delete_dialog @dialogHandle ;
SEND ON CONVERSATION @dialogHandle MESSAGE TYPE [EndOfStream];
END
ELSE
BEGIN
-- Free the dialog.
EXEC usp_free_dialog @dialogHandle, @sendCount;
END
COMMIT
END;
GO --------------------------------------------------------
-- Run application section
-------------------------------------------------------- -- Send some messages exec usp_send N'SsbInitiatorService', N'SsbTargetService', N'SsbContract', N'SsbMsgType', N'<xml>This is a well formed XML Message1.</xml>'
exec usp_send N'SsbInitiatorService', N'SsbTargetService', N'SsbContract', N'SsbMsgType', N'<xml>This is a well formed XML Message2.</xml>'
exec usp_send N'SsbInitiatorService', N'SsbTargetService', N'SsbContract', N'SsbMsgType', N'<xml>This is a well formed XML Message3.</xml>'
exec usp_send N'SsbInitiatorService', N'SsbTargetService', N'SsbContract', N'SsbMsgType', N'<xml>This is a well formed XML Message4.</xml>'
exec usp_send N'SsbInitiatorService', N'SsbTargetService', N'SsbContract', N'SsbMsgType', N'<xml>This is a well formed XML Message5.</xml>'
GO -- Show the dialog pool
SELECT * FROM [DialogPool]
GO -- Show the dialogs used.
SELECT * FROM sys.conversation_endpoints;
GO -- Check whether the TARGET side has processed the messages
SELECT * FROM MsgTable
SELECT * FROM dialogpool
SELECT * FROM dbo.target_processing_errors --TRUNCATE TABLE MsgTable
GO

Reusing dialogs with a dialog pool--一个sql server service broker例子的更多相关文章

  1. SQL Server Service Broker创建单个数据库会话

    概述 SQL Server Service Broker 用来创建用于交换消息的会话.消息在目标和发起方这两个端点之间进行交换.消息用于传输数据和触发消息收到时的处理过程.目标和发起方既可以在同一数据 ...

  2. SQL Server Service Broker创建单个数据库会话(消息队列)

    概述 SQL Server Service Broker 用来创建用于交换消息的会话.消息在目标和发起方这两个端点之间进行交换.消息用于传输数据和触发消息收到时的处理过程.目标和发起方既可以在同一数据 ...

  3. SQL Server Service Broker 简单例子 (转)

    SQL Server Service Broker服务体系结构 消息类型 — 定义应用程序间交换的消息的名称.还可以选择是否验证消息.约定 — 指定给定会话中的消息方向和消息类型.队列 — 存储消息. ...

  4. The SQL Server Service Broker for the current database is not enabled

    把一个数据恢复至另一个服务器上,出现了一个异常: The SQL Server Service Broker for the current database is not enabled, and ...

  5. SQL Server Service Broker(简称SSB)资料

    SQL server Service Broker (下面简称SSB) 是SQL server 里面比较独特的一个功能.它可帮助开发人员构建异步的松散耦合应用程序.SSB的一些功能和好处包括有: 数据 ...

  6. SQL问题:未启用当前数据库的 SQL Server Service Broker

    数据库分离后,附加回到数据库,然后在程序中打开调用数据库的页面,出现如下问题:“未启用当前数据库的 SQL Server Service Broker,因此查询通知不受支持.如果希望使用通知,请为此数 ...

  7. 在Windows Server 2008 R2 Server中,连接其他服务器的数据库遇到“未启用当前数据库的 SQL Server Service Broker,因此查询通知不受支持。如果希望使用通知,请为此数据库启用 Service Broker ”

    项目代码和数据库部署在不同的Windows Server 2008 R2 Server中,错误日志显示如下: "未启用当前数据库的 SQL Server Service Broker,因此查 ...

  8. sql server Service Broker 相关查询

    sql server Service Broker 相关查询 -- 查看传输队列中的消息 --如果尝试从队列中移除时,列将表明哪里出现了问题 select * from sys.transmissio ...

  9. java当中JDBC当中请给出一个sql server的helloworld例子

    [学习笔记] 1.sql server的helloworld例子: import java.sql.*; public class JdbcHelloSqlServer {  public stati ...

随机推荐

  1. 【轮廓线DP】POJ2411-Mondriaan's Dream

    今天美国的院士过来讲课XD以为会很无聊但是谜之好听,而且英语基本上都听懂了的样子♪(´▽`) 逃到图书馆来写解题报告 [题目大意] 给出一个m*n的方格,用2*1的骨牌覆盖有几种情况. [思路] 最基 ...

  2. 不思议迷宫:逆向后的放置play

    前言 前置准备 目标分析 逆向加密逻辑 定位sign与key 解密luac 反编译luajit的bytecode 开启上帝模式 前言     看了fatezero的<阴阳师:一个非酋的逆向旅程& ...

  3. bzoj 4780: [Usaco2017 Open]Modern Art 2

    4780: [Usaco2017 Open]Modern Art 2 Time Limit: 10 Sec  Memory Limit: 128 MB Description Having becom ...

  4. JavaScript设计模式与开发实践——读书笔记1.高阶函数(下)

    上部分主要介绍高阶函数的常见形式,本部分将着重介绍高阶函数的高级应用. 1.currying currying指的是函数柯里化,又称部分求值.一个currying的函数会先接受一些参数,但不立即求值, ...

  5. hdu 3340 Rain in ACStar 线段树区间等差数列更新

    Rain in ACStar Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 http://acm.hust.edu.cn/problem/show/1385 ...

  6. JSON数据转换到POCO的代码

    转载:http://www.cnblogs.com/wintersun/archive/2012/09/14/2684708.html 在Visual Studio 2012中轻松把JSON数据转换到 ...

  7. setTimeOut传參数

    function blink(e_Id, second) {var soccer = document.getElementById(e_Id); soccer.style.visibility = ...

  8. Shell编程入门(第二版)(中)

    注:test測试语句一般不单独使用,一般作为if语句的測试条件,如; if test -d file then .... fi test的变量的简写形式"[]" 演示样例-apac ...

  9. 第一章 在linux下python读串口 存MYSQL数据库(703N)

    import MySQLdb//定义引用数据库的驱动文件 import serial import time ser = serial.Serial('/dev/ttyATH0', 115200, t ...

  10. spring mvc 基于注解 配置默认 handlermapping

    spring mvc 是类似于 Struts 的框架.他们都有一个最主要的功能就是URL路由.URL路由能将请求与响应请求处理逻辑的类(在Struts中即是action,在spring mvc 中即是 ...