SERVICE BROKER

 建议大家先看微软官方的有关BROKER资料。备着以后使用。

http://msdn.microsoft.com/zh-cn/library/ms345108(SQL.90).aspx

然后再看下面的案例。因为下面的案例就是基于该上面的资料演示的。否则很难直接看懂该案例

同时谢谢该案例的作者 http://www.cnblogs.com/downmoon/archive/2011/04/05/2005900.html

 

 

创建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 int IDENTITY ( 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 ( @OrderID as varchar ( 10 )) + ' "/> ' ; SELECT @ResponseMsg = CAST ( @TextResponseMsg as xml); -- 使用既有的会话句柄,发送响应消息到发起方 SEND ON CONVERSATION @Conv_Handler MESSAGE TYPE [ //SackConsulting/BookOrderReceived ]
 

(十)、结束会话

  
  
-- Ending a Conversation USE BookStore GO -- 创建订单确认表 CREATE TABLE dbo.BookOrderConfirmation (BookOrderConfirmationID int IDENTITY ( 1 , 1 ) NOT NULL , conversation_handle uniqueidentifier NOT NULL , DateReceived datetime NOT NULL DEFAULT GETDATE (), message_body xml NOT NULL ) 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_Handler uniqueidentifier DECLARE @Conv_Group uniqueidentifier DECLARE @OrderMsg xml DECLARE @message_type_name nvarchar ( 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
 
 
Service Broker的设置会话优先级

  自SQL Server 2008起,对非常活跃的Service Broker应用程序,提供了设置优先级的命令CREATE BROKER PRIORITY(http://msdn.microsoft.com/en-us/library/bb934170.aspx)。通过该命令,可以设置从1至10共10个等级的颗粒度来调试会话的优先级,默认为5。在此之前,你必须得首先打开HONOR_BROKER_PRIORITY开关。

     
     
-- 设置会话优先级 -- 启用会话优先级选项 ALTER DATABASE BookStore SET HONOR_BROKER_PRIORITY ON -- 启用会话优先级选项 ALTER DATABASE BOOKDistribution SET HONOR_BROKER_PRIORITY ON -- 查看设置结果 SELECT name, is_honor_broker_priority_on FROM sys.databases WHERE name IN ( ' BookStore ' , ' BookDistribution ' ) /* name is_honor_broker_priority_on BookStore 1 BookDistribution 1 */ USE BookStore GO CREATE BROKER PRIORITY Conv_Priority_BookOrderContract_BookOrderService FOR CONVERSATION SET (CONTRACT_NAME = [ //SackConsulting/BookOrderContract ] , -- 特定的契约 LOCAL_SERVICE_NAME = [ //SackConsulting/BookOrderService ] , -- 本地服务 REMOTE_SERVICE_NAME = ANY , -- 远程服务为ANY,即Service Broker端点的任何相关服务 PRIORITY_LEVEL = 10 ) -- 设置优先级为10  

  通过sys.conversation_priorities目录视图,查询优先级

     
     
SELECT name, priority, service_contract_id, local_service_id,remote_service_name FROM sys.conversation_priorities cp /* name priority service_contract_id local_service_id remote_service_name Conv_Priority_BookOrderContract_BookOrderService 10 65536 65536 NULL */
如果你希望包含服务和契约名称,可以将服务和从sys.conversation_priorities( http://msdn.microsoft.com/zh-cn/library/bb895280%28v=sql.100%29.aspx)返回的契约ID与sys.service_contracts( http://msdn.microsoft.com/en-us/library/ms184378.aspx),sys.services( http://msdn.microsoft.com/en-us/library/ms174429.aspx)目录视图关联起来。
     
     
USE BookDistribution GO -- 创建目标服务的优先级,与发起方的优先级保持一致, -- 以使会话的优先级设置覆盖整个会话的生命周期 CREATE BROKER PRIORITY Conv_Priority_BookOrderContract_BookDistributionService FOR CONVERSATION SET (CONTRACT_NAME = [ //SackConsulting/BookOrderContract ] , LOCAL_SERVICE_NAME = [ //SackConsulting/BookDistributionService ] , REMOTE_SERVICE_NAME = ANY , PRIORITY_LEVEL = 10 ) USE BookStore GO ALTER BROKER PRIORITY Conv_Priority_BookOrderContract_BookOrderService FOR CONVERSATION SET (REMOTE_SERVICE_NAME = ' //SackConsulting/BookDistributionService ' ) -- 修改远程服务名称 ALTER BROKER PRIORITY Conv_Priority_BookOrderContract_BookOrderService FOR CONVERSATION SET (PRIORITY_LEVEL = 9 ) -- 设置优先级 -- 删除优先级设置 DROP BROKER PRIORITY Conv_Priority_BookOrderContract_BookOrderService

二、Service Broker的存储过程实现

  在上文中,我们使用的临时T-SQL来演示Service broker的步骤,事实上, 我们完全可以通过存储过程或外部应用程序自动激活并处理队列中的消息。使用Create Queue(http://msdn.microsoft.com/en-us/library/ms190495.aspx)和Alter Queue(http://msdn.microsoft.com/en-us/library/ms189529.aspx)选项,也可以指定可以激活并处理在同一队列中传入的消息的、同时执行的相同服务程序的数量。

  继续上文的示例:

     
     
-- Creating the Bookstore Stored Procedure USE BookDistribution GO CREATE PROCEDURE dbo.usp_SB_ReceiveOrders AS DECLARE @Conv_Handler uniqueidentifier DECLARE @Conv_Group uniqueidentifier DECLARE @OrderMsg xml DECLARE @TextResponseMsg varchar ( 8000 ) DECLARE @ResponseMsg xml DECLARE @Message_Type_Name nvarchar ( 256 ); DECLARE @OrderID int ; -- XACT_ABORT automatically rolls back the transaction when a runtime error occurs SET XACT_ABORT ON BEGIN TRAN ; RECEIVE TOP ( 1 ) @OrderMsg = message_body, @Conv_Handler = conversation_handle, @Conv_Group = conversation_group_id, @Message_Type_Name = message_type_name FROM dbo.BookDistributionQueue; IF @Message_Type_Name = ' //SackConsulting/SendBookOrder ' BEGIN INSERT dbo.BookOrderReceived (conversation_handle, conversation_group_id, message_body) VALUES ( @Conv_Handler , @Conv_Group , @OrderMsg ) SELECT @OrderID = @OrderMsg .value( ' (/order/@id)[1] ' , ' int ' ) SELECT @TextResponseMsg = ' <orderreceived id= " ' + CAST ( @OrderID as varchar ( 10 )) + ' "/> ' ; SELECT @ResponseMsg = CAST ( @TextResponseMsg as xml); SEND ON CONVERSATION @Conv_Handler MESSAGE TYPE [ //SackConsulting/BookOrderReceived ] ( @ResponseMsg ); END IF @Message_Type_Name = ' http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog ' BEGIN END CONVERSATION @Conv_Handler ; END COMMIT TRAN GO

  解析:该存储过程包含处理//SackConsulting/SendBookOrder和http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog消息类型的逻辑。如果发送发后者,特定会话的句柄的特定会话会结束。如果接收到图书订单消息类型,它的消息将插入到表中,并且返回订单确认信息。

  可以使用Alter Queue命令修改既有的队列。这个命令使用与Create Queue相同的选项,它允许改变队列的状态与保持期、待激活的存储过程、队列读取存储过程实例的最大数量以及过程的安全模式契约。

  Alter Queue包括一个额外的参数Drop,它用来删除队列的所有存储过程激活设置。

  使用Alter Queue命令将存储过程绑定到既有的队列:

     
     
-- --使用Alter Queue命令将存储过程绑定到既有的队列 ALTER QUEUE dbo.BookDistributionQueue WITH ACTIVATION (STATUS = ON , PROCEDURE_NAME = dbo.usp_SB_ReceiveOrders, MAX_QUEUE_READERS = 2 , -- 独立处理队列中不同消息的同一存储过程同时执行的最大数量 EXECUTE AS SELF) -- 即存储过程将以与执行Alter Queue命令的主体的相同的权限来执行

为了测试BookStore数据库的新服务程序,开始一个会话并设置新顺序:

     
     
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="3490" customer="29" orderdate="7/22/2008"> <LineItem ItemNumber="1" ISBN="1-59059-592-0" Quantity="2" /> </order> ' ; SEND ON CONVERSATION @Conv_Handler MESSAGE TYPE [ //SackConsulting/SendBookOrder ] ( @OrderMsg );

  当队列Status=ON并且队列中到到达新消息时,执行存储过程来处理传入的消息。可以使用存储过程或外部程序,但使用存储过程的好处是,它们提供了处理消息、自动执行所有需要的响应和相关业务任务的简单的封装好的组件。

  如果在目标队列上有存储过程被执行,并且激活新的接收到的消息,那么应该已经有订单确认消息返回到dbo.BookStoreQueue:

     
     
SELECT conversation_handle, CAST (message_body as xml) message FROM dbo.BookStoreQueue /* conversation_handle message A7B7FA73-5B5F-E011-8B4E-001C23FA56DD <orderreceived id="3439" /> */
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SQL Server 2005 的一个要成就是可以实现可靠、可扩展且功能完善的数据库应用程序。与 .NET Framework 2.0 公共语言运行库 (CLR) 的集成使开发人员可以将重要的业务逻辑与存储过程合并,而 T-SQL 和 XML 的新增功能扩展了数据操作的可用范围以及开发人员可用的存储功能。另一个重要功能是 SQL Server Service Broker,它为数据库应用程序增加了可靠、可扩展、分布式异步功能。 为什么要编写异步排队操作? 在开发 SQL Server 2005 时,我们与成功开发过大型可扩展数据库应用程序的人员进行了交谈。结果发现他们几乎所有的应用程序都有一个或多个操作是以异步排队方式执行的。股票交易系统的结算活动是排队的,这样可以在后台进行结算,在前端处理其他交易。订单输入系统的发货信息放在一个排队,稍后将由另一台服务器(通常位于其他位置)上运行的发货系统读取。旅行预订系统在客户填写完路线后再进行实际的预订,并在预订完成后发送确认电子邮件。在所有这些示例,许多工作都是通过异步方式完成的,从而提高了系统的响应速度,因此用户无须等待工作完成就可以收到响应。 在大多数大型系统,经过仔细分析后都可以发现,许多处理都可以通过异步方式完成。虽然应用程序的排队任务无须立即完成,但系统必须确保这些任务能够可靠地完成。Service Broker 使异步排队任务的执行可靠并且易于实现。 使应用程序的部分任务异步执行的另一个优势是这些任务的处理工作可以在资源可用时完成。如果订单输入系统的发货任务可以从队列执行,发货系统就无需具有处理峰值订单负载的能力。在许多订单输入系统,峰值订单率可能是平均订单率的两倍或三倍。由于订单输入系统必须具有处理峰值负载的能力,因此大量处理能力在很大一部分时间内都处于闲置状态。如果在出现峰值时对异步任务进行排队并在空闲时执行,将显著提高系统的利用率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值