• Service Broker 消息队列的方式实现数据同步


    SQL Server 2008中SQL应用系列--目录索引

    导读:本文主要涉及Service Broker的基本概念及建立一个Service Broker应用程序的基本步骤。

    一、前言

         Service Broker为SQL Server提供消息队列,这提供了从数据库中发送异步事务性消息队列的方法。Service Broker消息可以保证以适当的顺序或原始的发送顺序不重复地一次性接收。并且因为内建在SQL Server中,这些消息在数据库发生故障时是可以恢复的,也可以随数据库一起备份。在SQL Server 2008中,还引入了使用Create Broker Priority命令对会话设定优先级,可以对重要的或不重要的会话进行优先级设定,以保证消息合理地处理。

         本文假定一个在线数据库BookStore中存储了一些业务订单。我们使用Service Broker应用程序将消息发送到另一个数据库BookDistribution,该数据库是分离的应用程序调用,该应用程序控制仓库入库和出库交付, 并返回消息给BookStore。

        创建Service Broker应用程序大体步骤如下:

    1、定义希望应用程序执行的异步任务。

    2、确定Service Broker的发起方服务和目标服务是否创建在同一个SQL Server实例中。如果是两个实例,实例间的通信还需要创建经过证书认证或NT安全的身份认证,并且要创建端点、路由以及对话安全模式。

    3、如果没有启用,则在多方参与的数据库中使用Alter Database命令设置Enable_broker以及Truseworthy数据库选项。

    4、为所有多方参与的数据库创建数据库主密钥。

    5、创建希望在服务之间发送的消息类型。

    6、创建契约(Contract)来定义可以由发起方发送的各种消息以及由目标发送的消息类型的种类。

    7、同时在两方参与的数据库中创建用于保存消息的队列。

    8、同时在绑定特定约定到特定队列的多方参与的数据库中创建服务。

    二、实例

        下面我们通过一个示例来实现以上步骤:

    (一)、启用数据库的Service Broker活动

    复制代码
    -- Enabling Databases for Service Broker Activity

    USE master
    GO
    IF NOT EXISTS (SELECT name FROM sys.databases WHERE name ='BookStore')
    CREATE DATABASE BookStore
    GO
    IF NOT EXISTS (SELECT name FROM sys.databases WHERE name ='BookDistribution')
    CREATE DATABASE BookDistribution
    GO
    ALTER DATABASE BookStore SET ENABLE_BROKER
    GO
    ALTER DATABASE BookStore SET TRUSTWORTHY ON
    GO
    ALTER DATABASE BookDistribution SET ENABLE_BROKER
    GO
    ALTER DATABASE BookDistribution SET TRUSTWORTHY ON
    复制代码

    (二)、创建数据库主密钥

    复制代码
    -- Creating the DatabaseMaster Key for Encryption

    USE BookStore
    GO
    CREATE MASTER KEY
    ENCRYPTION
    BY PASSWORD ='I5Q7w1d3'
    GO

    USE BookDistribution
    GO
    CREATE MASTER KEY
    ENCRYPTION
    BY PASSWORD ='D1J3q5z8X6y4'
    GO
    复制代码

    (三)、管理消息类型

    使用CREATE MESSAGE TYPE(http://msdn.microsoft.com/en-us/library/ms187744.aspx)命令,

    复制代码
    -- Managing Message Types

    Use BookStore
    GO
    -- 发送图书订单的消息类型
    CREATE MESSAGE TYPE [//SackConsulting/SendBookOrder]
    VALIDATION
    = WELL_FORMED_XML
    GO

    --目标数据库发送的消息类型
    CREATE MESSAGE TYPE [//SackConsulting/BookOrderReceived]
    VALIDATION
    = WELL_FORMED_XML
    GO

    --执行同样的定义
    Use BookDistribution
    GO
    -- 发送图书订单的消息类型
    CREATE MESSAGE TYPE [//SackConsulting/SendBookOrder]
    VALIDATION
    = WELL_FORMED_XML
    GO

    --目标数据库发送的消息类型
    CREATE MESSAGE TYPE [//SackConsulting/BookOrderReceived]
    VALIDATION
    = WELL_FORMED_XML
    GO
    复制代码

    --注意,此处没有定义消息的内容。实际的消息是消息类型的实例。

    (四)、创建契约(Contract)

    使用Create Contract(http://msdn.microsoft.com/en-us/library/ms178528.aspx

    复制代码
    -- Creating Contracts

    Use BookStore
    GO
    CREATE CONTRACT
    [//SackConsulting/BookOrderContract]
    (
    [//SackConsulting/SendBookOrder]
    SENT
    BY INITIATOR,
    [//SackConsulting/BookOrderReceived]
    SENT
    BY TARGET
    )
    GO

    USE BookDistribution
    GO
    CREATE CONTRACT
    [//SackConsulting/BookOrderContract]
    (
    [//SackConsulting/SendBookOrder]
    SENT
    BY INITIATOR,
    [//SackConsulting/BookOrderReceived]
    SENT
    BY TARGET
    )
    GO
    复制代码

    --发起方和目标的定义必须相同

    (五)、创建队列

    队列用来保存数据。使用命令Create queue(http://msdn.microsoft.com/en-us/library/ms190495.aspx

    复制代码
    -- Creating Queues

    Use BookStore
    GO
    --保存BookDistribution过来的消息
    CREATE QUEUE BookStoreQueue
    WITH STATUS=ON
    GO

    USE BookDistribution
    GO
    --保存BookStore过来的消息
    CREATE QUEUE BookDistributionQueue
    WITH STATUS=ON
    GO
    复制代码

    (六)、创建服务

    服务定义端点,然后使用它来将消息队列绑定到一个或多个契约上。服务使用队列和契约来定义一个或一组任务。有点拗口,是不是?

    服务是消息的发起方和接收方强制约定的规则,并将消息路由到正确的序列。

    使用Create Service(http://msdn.microsoft.com/en-us/library/ms190332.aspx)命令。

    复制代码
    -- Creating Services

    Use BookStore
    GO
    CREATE SERVICE [//SackConsulting/BookOrderService]
    ON QUEUE dbo.BookStoreQueue--指定的队列绑定到契约
    ([//SackConsulting/BookOrderContract])
    GO

    USE BookDistribution
    GO
    CREATE SERVICE [//SackConsulting/BookDistributionService]
    ON QUEUE dbo.BookDistributionQueue--指定的队列绑定到契约
    ([//SackConsulting/BookOrderContract])
    GO
    复制代码

    (七)、启动对话

    对话会话(dialog conservation)是在服务之间进行消息交换的操作。

    使用Begin Dialog Conversation(http://msdn.microsoft.com/en-us/library/ms187377.aspx) 命令创建新的会话。使用Send(http://msdn.microsoft.com/en-us/library/ms188407.aspx)来发送消息。使用End Conversation命令(http://msdn.microsoft.com/en-us/library/ms177521.aspx)结束会话。

    复制代码
    -- Initiating a Dialog

    Use BookStore
    GO

    --保存会话句柄和订单信息
    DECLARE @Conv_Handler uniqueidentifier
    DECLARE @OrderMsg xml;

    BEGIN DIALOG CONVERSATION @Conv_Handler--创建会话
    FROM SERVICE [//SackConsulting/BookOrderService]
    TO SERVICE '//SackConsulting/BookDistributionService'
    ON CONTRACT [//SackConsulting/BookOrderContract];
    SET@OrderMsg=
    '<order id="3439" customer="22" orderdate="2/15/2011">
    <LineItem ItemNumber="1" ISBN="1-59059-592-0" Quantity="1" />
    </order>
    ';
    SEND
    ON CONVERSATION @Conv_Handler--发送到BookDistribution数据库的队列中
    MESSAGE TYPE [//SackConsulting/SendBookOrder]
    (
    @OrderMsg);
    复制代码

    (八)、查询队列中传入的消息

    复制代码
    -- Querying the Queue for IncomingMessages

    USE BookDistribution
    GO
    SELECT message_type_name, CAST(message_body as xml) message,
    queuing_order, conversation_handle, conversation_group_id
    FROM dbo.BookDistributionQueue
    复制代码

    查询结果:

    邀月工作室

    (九)、检索并响应消息

    使用Receive语句(http://msdn.microsoft.com/en-us/library/ms186963.aspx)从队列中读取行(消息),也可以删除已经读取的消息。Receive的结果可以填充到常规表中,也可以在局部变量中执行其他操作,或发送到其他service Broker消息。如果消息是XML数据类型的消息,则可以直接借助TSQL的XQuery来操作。

    复制代码
    -- Receiving and Responding to aMessage

    USE BookDistribution
    GO
    --创建一个表存放接收到的订单信息
    CREATE TABLE dbo.BookOrderReceived
    (BookOrderReceivedID
    intIDENTITY (1,1) NOT NULL,
    conversation_handle
    uniqueidentifier NOT NULL,
    conversation_group_id
    uniqueidentifier NOT NULL,
    message_body xml
    NOT NULL)
    GO

    -- 声明变量
    DECLARE @Conv_Handler uniqueidentifier
    DECLARE @Conv_Group uniqueidentifier
    DECLARE @OrderMsg xml
    DECLARE @TextResponseMsg varchar(8000)
    DECLARE @ResponseMsg xml
    DECLARE @OrderID int;

    --从队列中获取消息,将接收值赋于局部变量
    RECEIVE TOP(1) @OrderMsg= message_body,--TOP指定最多一条消息
    @Conv_Handler= conversation_handle,
    @Conv_Group= conversation_group_id
    FROM dbo.BookDistributionQueue;

    -- 将变量值插入表中
    INSERT dbo.BookOrderReceived
    (conversation_handle, conversation_group_id, message_body)
    VALUES
    (
    @Conv_Handler,@Conv_Group, @OrderMsg )

    -- 使用XQuery进行抽取以响应消息订单
    SELECT @OrderID=@OrderMsg.value('(/order/@id)[1]', 'int' )
    SELECT @TextResponseMsg=
    '<orderreceived id= "'+
    CAST(@OrderIDasvarchar(10)) +
    '"/>';
    SELECT @ResponseMsg=CAST(@TextResponseMsgas xml);

    -- 使用既有的会话句柄,发送响应消息到发起方
    SEND ON CONVERSATION @Conv_Handler
    MESSAGE TYPE
    [//SackConsulting/BookOrderReceived]
    (@OrderMsg)
    复制代码

    (十)、结束会话

    复制代码
    -- Ending a Conversation

    USE BookStore
    GO
    -- 创建订单确认表
    CREATETABLE dbo.BookOrderConfirmation
    (BookOrderConfirmationID
    intIDENTITY (1,1) NOTNULL,
    conversation_handle
    uniqueidentifierNOTNULL,
    DateReceived
    datetimeNOTNULLDEFAULTGETDATE(),
    message_body xml
    NOTNULL)

    DECLARE @Conv_Handler uniqueidentifier
    DECLARE @Conv_Group uniqueidentifier
    DECLARE @OrderMsg xml
    DECLARE @TextResponseMsg varchar(8000);

    RECEIVE
    TOP(1) @Conv_Handler= conversation_handle,
    @OrderMsg= message_body
    FROM dbo.BookStoreQueue

    INSERT dbo.BookOrderConfirmation
    (conversation_handle, message_body)
    VALUES (@Conv_Handler,@OrderMsg );

    END CONVERSATION @Conv_Handler;
    GO

    USE BookDistribution
    GO
    DECLARE @Conv_Handleruniqueidentifier
    DECLARE @Conv_Groupuniqueidentifier
    DECLARE @OrderMsg xml
    DECLARE @message_type_namenvarchar(256);

    RECEIVE
    TOP(1) @Conv_Handler= conversation_handle,
    @OrderMsg= message_body,
    @message_type_name= message_type_name
    FROM dbo.BookDistributionQueue

    -- 双方必须都结束会话
    IF
    @message_type_name='http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog'
    BEGIN
    END CONVERSATION @Conv_Handler;
    END
    复制代码

    --查询会话状态

    SELECT state_desc, conversation_handle
    FROM sys.conversation_endpoints

    邀月工作室

    三、小结

    本文通过一个实例演示了一个用来发送图书订单消息分发控制数据库的简单的消息交换应用程序。发起方发送图书订单,发回一个响应,并在两个数据库上使用END Conservation结束会话。现实场景中可以转换为其他消息类型、契约、服务和队列。合理运用Service Broker应用程序的异步特性可以防止因应用程序挂起而导致业务系统产生瓶颈。

    本文参考:

    1、SQL Server 2005 Service Broker 初探

    http://msdn.microsoft.com/zh-cn/library/ms345108%28v=sql.90%29.aspx

    2、SQL Server 2008 Transact-SQL Recipes: A Problem-Solution Approach

    http://www.amazon.com/Server-2008-Transact-SQL-Recipes-Problem-Solution/dp/1590599802

     
     
     
  • 相关阅读:
    【mysql中文乱码】-解决方式
    【URL带参跳转乱码】-解决方式
    【IP地址租约到期】-解决方式
    【Vue-入门笔记-5】
    【Vue-入门笔记-4】
    输入框中的空"",0,null的判断
    让页面以黑白页面显示
    select设置text的值选中(兼容ios和Android)基于jquery
    js中关于两个变量的比较
    css3 动画 总结
  • 原文地址:https://www.cnblogs.com/linybo/p/12028632.html
Copyright © 2020-2023  润新知