Service Broker 消息队列的方式实现数据同步
导读:本文主要涉及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
Service Broker 消息队列的方式实现数据同步的更多相关文章
- BizTalk 开发系列(四十) BizTalk WCF-SQL Adapter读取SQL Service Broker消息
SQL Service Broker 是在SQL Server 2005中新增的功能.Service Broker 为 SQL Server 提供队列和可靠的消息传递,可以可用来建立以异步消息为基础的 ...
- RabbitMQ和Kafka,更加便捷高效的消息队列使用方式,请放心食用
一.RabbitMQ实例介绍RabbitMQ实例由华为云分布式消息服务(DMS)团队打造,实例采用物理隔离的方式部署,租户独占RabbitMQ实例.一键式部署,完全兼容开源RabbitMQ的使用方式, ...
- HTTPSQS(HTTP Simple Queue Service)消息队列
HTTPSQS(HTTP Simple Queue Service)是一款基于 HTTP GET/POST 协议的轻量级开源简单消息队列服务,使用 Tokyo Cabinet 的 B+Tree Key ...
- Linux下进程间通信方式——使用消息队列
一.什么是消息队列 消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法. 每个数据块都被认为含有一个类型,接收进程可以独立地接收含有不同类型的数据结构.我们可以通过发送消息来避免命名管道的 ...
- 启动任务StartTask() 发送完消息队列 自己删除,接收方一直显示数据 用OSQFlush(Str_Q); //清空消息队列 下面纠结接收不到了 哈哈
在建立工程的时候,启动任务StartTask() 启动了任务MyTask(),也建立了消息队列,然后发送消息队列,发送完自己删除了自己,在接收方一直能接受到数据???为何??? 因为我们的消息队列未 ...
- SQL Server 2005 Service Broker
一.引言 SQL Server 2005 的一个主要成就是可以实现可靠.可扩展且功能完善的数据库应用程序.与 .NET Framework 2.0 公共语言运行库 (CLR) 的集成使开发人员可以将重 ...
- Python并发编程-RabbitMQ消息队列
RabbitMQ队列 RabbitMQ是一个在AMQP基础上完整的,可复用的企业消息系统.他遵循Mozilla Public License开源协议. MQ全称为Message Queue, 消息队列 ...
- 分布式消息队列XXL-MQ
<分布式消息队列XXL-MQ> 一.简介 1.1 概述 XXL-MQ是一款轻量级分布式消息队列,支持串行.并行和广播等多种消息模型.现已开放源代码,开箱即用. 支持三种消息模式: ...
- 应用服务器性能优化 之 消息队列(MQ:Message Queue)
一,消息队列基本概念 借用百科的一句话:消息队列就是在消息的传输过程中,保存消息的容器. 从图-1和图-2对比,可以很清晰的明白,消息队列服务器,是位于应用服务器和数据库服务器之间的一个服务器.消息队 ...
随机推荐
- GraphQL学习之原理篇
前言 在上一篇文章基础篇中,我们介绍了GraphQL的语法以及类型系统,算是对GraphQL有个基本的认识.在这一篇中,我们将会介绍GraphQL的实现原理.说到原理,我们就不得不依托于GraphQL ...
- 【c# 学习笔记】面向对象编程的应用
在平时的开发过程中,面向对象编程的应用肯定必不可少.但前面的内容只是单独介绍了类.面向对象思想和接口,那么我们怎么在平时工作中来应用他们来实现面向对象编程呢? 如果你想设计一个Dog类,有了类的概念后 ...
- 【VS2015软件报错】命名空间 system.windows 中不存在类型或命名空间名称 forms (是否缺少程序集引用 )错误
C#项目: 添加“using System.Windows.Forms;”之后提示“命名空间 system.windows 中不存在类型或命名空间名称 forms (是否缺少程序集引用 )”错误 详细 ...
- Python-Web-数据库-mongodb
理念: ----无创建数据库方法,使用即创建 ----里面无数据,即数据库不存在 ----数据库有表,表里有一条数据,则数据库存在 ----表数据为JSON格式[{‘name’:’lisi’,’age ...
- DSP6455的EMIFA口
DSP6455的EMIFA口 声明:引用请注明出处http://blog.csdn.net/lg1259156776/ 支持两种不同的接口模式: 异步接口:标准的SRAM,ROM接口 同步接口:SBS ...
- C/C++.控制台输入(cin/getchar)
1.类似的函数有:cin.getchar.fgetc 等 2.问题: 最后的"\n"都不取出来... 2.1.对策:(ZC:下面是 我自己使用后的感受) (1)fflush(std ...
- APK在Android Studio下如何签名
apk签名的意义 Android系统要求每一个Android应用程序必须要经过数字签名才能够安装到系统中,也就是说如果一个Android应用程序没有经过数字签名,是没有办法安装到系统中的! Andro ...
- bzoj3624(Apio2008):免费道路
题目↓ Sample Input 5 7 2 1 3 0 4 5 1 3 2 0 5 3 1 4 3 0 1 2 1 4 2 1 Sample Output 3 2 0 4 3 0 5 3 1 1 2 ...
- SQL-TSQL
一.系统存储过程 常用 sp_helptext --查看可编程性(存储过程.函数.触发器.规则.默认值),表中(约束.触发器) EXEC sp_helptext f_M_Student 二.全局变量 ...
- 并发艺术--java并发机制的底层实现原理
前言 Java代码在编译后会变成Java字节码,字节码被类加载器加载到JVM里,JVM执行字节码,最终需要转化为汇编指令在CPU上执行,Java中所使用的并发机制依赖于JVM的实现和CPU的指令. 一 ...