SQL Server 2008中Service Broker基础应用(上)

来源:互联网 发布:加缪手记淘宝 编辑:程序博客网 时间:2024/05/23 01:19

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活动

[ruby] view plaincopyprint?
  1. -- Enabling Databases for Service Broker Activity  
  2. USE master  
  3. GO  
  4. IF NOT EXISTS (SELECT name FROM sys.databases WHERE name = 'BookStore')  
  5. CREATE DATABASE BookStore  
  6. GO  
  7. IF NOT EXISTS (SELECT name FROM sys.databases WHERE name = 'BookDistribution')  
  8. CREATE DATABASE BookDistribution  
  9. GO  
  10. ALTER DATABASE BookStore SET ENABLE_BROKER  
  11. GO  
  12. ALTER DATABASE BookStore SET TRUSTWORTHY ON  
  13. GO  
  14. ALTER DATABASE BookDistribution SET ENABLE_BROKER  
  15. GO  
  16. ALTER DATABASE BookDistribution SET TRUSTWORTHY ON  

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

[ruby] view plaincopyprint?
  1. -- Creating the DatabaseMaster Key for Encryption  
  2. USE BookStore  
  3. GO  
  4. CREATE MASTER KEY  
  5. ENCRYPTION BY PASSWORD = 'I5Q7w1d3'  
  6. GO  
  7. USE BookDistribution  
  8. GO  
  9. CREATE MASTER KEY  
  10. ENCRYPTION BY PASSWORD = 'D1J3q5z8X6y4'  
  11. GO  

 

(三)、管理消息类型

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

[ruby] view plaincopyprint?
  1. -- Managing Message Types  
  2. Use BookStore  
  3. GO  
  4. -- 发送图书订单的消息类型  
  5. CREATE MESSAGE TYPE [//SackConsulting/SendBookOrder]  
  6. VALIDATION = WELL_FORMED_XML  
  7. GO  
  8. --目标数据库发送的消息类型  
  9. CREATE MESSAGE TYPE [//SackConsulting/BookOrderReceived]  
  10. VALIDATION = WELL_FORMED_XML  
  11. GO  
  12. --执行同样的定义  
  13. Use BookDistribution  
  14. GO  
  15. -- 发送图书订单的消息类型  
  16. CREATE MESSAGE TYPE [//SackConsulting/SendBookOrder]  
  17. VALIDATION = WELL_FORMED_XML  
  18. GO  
  19. --目标数据库发送的消息类型  
  20. CREATE MESSAGE TYPE [//SackConsulting/BookOrderReceived]  
  21. VALIDATION = WELL_FORMED_XML  
  22. GO   

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

(四)、创建契约(Contract)

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

[ruby] view plaincopyprint?
  1. -- Creating Contracts  
  2. Use BookStore  
  3. GO  
  4. CREATE CONTRACT  
  5. [//SackConsulting/BookOrderContract]  
  6. ( [//SackConsulting/SendBookOrder]  
  7. SENT BY INITIATOR,  
  8. [//SackConsulting/BookOrderReceived]  
  9. SENT BY TARGET  
  10. )  
  11. GO  
  12. USE BookDistribution  
  13. GO  
  14. CREATE CONTRACT  
  15. [//SackConsulting/BookOrderContract]  
  16. ( [//SackConsulting/SendBookOrder]  
  17. SENT BY INITIATOR,  
  18. [//SackConsulting/BookOrderReceived]  
  19. SENT BY TARGET  
  20. )  
  21. GO  

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

(五)、创建队列

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

[ruby] view plaincopyprint?
  1. -- Creating Queues  
  2. Use BookStore  
  3. GO  
  4. --保存BookDistribution过来的消息  
  5. CREATE QUEUE BookStoreQueue  
  6. WITH STATUS=ON  
  7. GO  
  8. USE BookDistribution  
  9. GO  
  10. --保存BookStore过来的消息  
  11. CREATE QUEUE BookDistributionQueue  
  12. WITH STATUS=ON  
  13. GO  

(六)、创建服务

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

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

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

[ruby] view plaincopyprint?
  1. -- Creating Services  
  2. Use BookStore  
  3. GO  
  4. CREATE SERVICE [//SackConsulting/BookOrderService]  
  5. ON QUEUE dbo.BookStoreQueue--指定的队列绑定到契约  
  6. ([//SackConsulting/BookOrderContract])  
  7. GO  
  8. USE BookDistribution  
  9. GO  
  10. CREATE SERVICE [//SackConsulting/BookDistributionService]  
  11. ON QUEUE dbo.BookDistributionQueue--指定的队列绑定到契约  
  12. ([//SackConsulting/BookOrderContract])  
  13. 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)结束会话。

[ruby] view plaincopyprint?
  1. -- Initiating a Dialog  
  2. Use BookStore  
  3. GO  
  4. --保存会话句柄和订单信息  
  5. DECLARE @Conv_Handler uniqueidentifier  
  6. DECLARE @OrderMsg xml;  
  7. BEGIN DIALOG CONVERSATION @Conv_Handler--创建会话  
  8. FROM SERVICE [//SackConsulting/BookOrderService]  
  9. TO SERVICE '//SackConsulting/BookDistributionService'  
  10. ON CONTRACT [//SackConsulting/BookOrderContract];  
  11. SET @OrderMsg =  
  12. '<order id="3439" customer="22" orderdate="2/15/2011">  
  13. <LineItem ItemNumber="1" ISBN="1-59059-592-0" Quantity="1" />  
  14. </order>';  
  15. SEND ON CONVERSATION @Conv_Handler--发送到BookDistribution数据库的队列中  
  16. MESSAGE TYPE [//SackConsulting/SendBookOrder]  
  17. (@OrderMsg);  

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

[c-sharp] view plaincopyprint?
  1. -- Querying the Queue for IncomingMessages  
  2. USE BookDistribution  
  3. GO  
  4. SELECT message_type_name, CAST(message_body as xml) message,  
  5. queuing_order, conversation_handle, conversation_group_id  
  6. FROM dbo.BookDistributionQueue   

查询结果:

邀月工作室

(九)、检索并响应消息

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

[ruby] view plaincopyprint?
  1. -- Receiving and Responding to aMessage  
  2. USE BookDistribution  
  3. GO  
  4. --创建一个表存放接收到的订单信息  
  5. CREATE TABLE dbo.BookOrderReceived  
  6. (BookOrderReceivedID int IDENTITY (1,1) NOT NULL,  
  7. conversation_handle uniqueidentifier NOT NULL,  
  8. conversation_group_id uniqueidentifier NOT NULL,  
  9. message_body xml NOT NULL)  
  10. GO  
  11. -- 声明变量  
  12. DECLARE @Conv_Handler uniqueidentifier  
  13. DECLARE @Conv_Group uniqueidentifier  
  14. DECLARE @OrderMsg xml  
  15. DECLARE @TextResponseMsg varchar(8000)  
  16. DECLARE @ResponseMsg xml  
  17. DECLARE @OrderID int;  
  18. --从队列中获取消息,将接收值赋于局部变量  
  19. RECEIVE TOP(1) @OrderMsg = message_body,--TOP指定最多一条消息  
  20. @Conv_Handler = conversation_handle,  
  21. @Conv_Group = conversation_group_id  
  22. FROM dbo.BookDistributionQueue;  
  23. -- 将变量值插入表中  
  24. INSERT dbo.BookOrderReceived  
  25. (conversation_handle, conversation_group_id, message_body)  
  26. VALUES  
  27. (@Conv_Handler,@Conv_Group@OrderMsg )  
  28. -- 使用XQuery进行抽取以响应消息订单  
  29. SELECT @OrderID = @OrderMsg.value('(/order/@id)[1]''int' )  
  30. SELECT @TextResponseMsg =  
  31. '<orderreceived id= "' +  
  32. CAST(@OrderID as varchar(10)) +  
  33. '"/>';  
  34. SELECT @ResponseMsg = CAST(@TextResponseMsg as xml);  
  35. -- 使用既有的会话句柄,发送响应消息到发起方  
  36. SEND ON CONVERSATION @Conv_Handler  
  37. MESSAGE TYPE [//SackConsulting/BookOrderReceived](@OrderMsg)   

 

 

(十)、结束会话

[c-sharp] view plaincopyprint?
  1. -- Ending a Conversation  
  2. USE BookStore  
  3. GO  
  4. -- 创建订单确认表  
  5. CREATE TABLE dbo.BookOrderConfirmation  
  6. (BookOrderConfirmationID int IDENTITY (1,1) NOT NULL,  
  7. conversation_handle uniqueidentifier NOT NULL,  
  8. DateReceived datetime NOT NULL DEFAULT GETDATE(),  
  9. message_body xml NOT NULL)  
  10. DECLARE @Conv_Handler uniqueidentifier  
  11. DECLARE @Conv_Group uniqueidentifier  
  12. DECLARE @OrderMsg xml  
  13. DECLARE @TextResponseMsg varchar(8000);  
  14. RECEIVE TOP(1) @Conv_Handler = conversation_handle,  
  15. @OrderMsg = message_body  
  16. FROM dbo.BookStoreQueue  
  17. INSERT dbo.BookOrderConfirmation  
  18. (conversation_handle, message_body)  
  19. VALUES (@Conv_Handler,@OrderMsg );  
  20. END CONVERSATION @Conv_Handler;  
  21. GO  
  22. USE BookDistribution  
  23. GO  
  24. DECLARE @Conv_Handler uniqueidentifier  
  25. DECLARE @Conv_Group uniqueidentifier  
  26. DECLARE @OrderMsg xml  
  27. DECLARE @message_type_name nvarchar(256);  
  28. RECEIVE TOP(1) @Conv_Handler = conversation_handle,  
  29. @OrderMsg = message_body,  
  30. @message_type_name = message_type_name  
  31. FROM dbo.BookDistributionQueue  
  32. -- 双方必须都结束会话  
  33. IF  
  34. @message_type_name = 'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog'  
  35. BEGIN  
  36. END CONVERSATION @Conv_Handler;  
  37. END   

 

[ruby] view plaincopyprint?
  1. --查询会话状态  
  2. SELECT state_desc, conversation_handle  
  3. 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

 

 

邀月注:本文版权由邀月和CSDN共同所有,转载请注明出处。
助人等于自助!   3w@live.cn



版权声明:本文为博主原创文章,未经博主允许不得转载。

0 0