拓狼 - 5/24/2007 3:27:00 PM
使用Service Broker和其他数据库服务器进行会话--王成辉翻译整理,转贴请注明出自微软BI开拓者www.windbi.com
--原帖地址本文将讨论SQLServer2005的另一个新特点:Service Broker。简单的说,在SQLServer2005里,Service Broker就是分布式消息架构或者MSMQ(微软消息队列)。使用这个新特点,你可以给你的数据库应用程序添加可靠的、可升级的异步功能。本文将介绍这个新特点的好处和应用程序的基本配置。基于消息的应用程序的好处在详细描述Service Broker的特点和功能之前,让我们回顾一下基于消息的应用程序的好处。当几个服务会话时基于应用程序的消息是非常需要的。例如,在一个在线交易应用程序里,在顾客提交订单之前,你需要执行几个过程如检查库存可用性、运输可用性、发货日期等等。这些过程需要时间。如果你在订单提交之前正在验证所有的这些过程,你的顾客也许不得不在他的浏览器上等待一段时间。然而,你可以利用顾客的详细订单,通过把这些信息做成消息来处理所有需要处理的过程。在从所有服务那里得到信息后,你可以编辑这些信息,然后用电子邮件发生给顾客。这样,你的顾客就不用长时间的在你的网站上等待了,这样可以使其变得更友好。基于应用程序的消息能一次处理几个服务。例如,运输服务和库存可用性服务能并行运行。这样做可以最小化整个订单处理所需的时间。微软消息队列(MSMQ)是支持这种消息的一个架构。你可以用VB、C#或C++写应用程序去实现MSMQ应用程序。然而,对于交易信息应用程序的一个基本问题是当一个处理失败时你不得不手动回滚所有其他的操作,这不得不小心处理。也不是意见容易的事。SQLServer2005提出了这个新的特点来来解决这个交易信息问题。安装Service Broker仅需最小的配置,并且在所有的SQLServer版本里都可用。在SQLServer Express版本里,你可以使用Service Broker的客户端特点。在Service Broker里我们需要理解有一些概念和对象:Queues(队列)、Messages(消息)、Dialogs(对话)、Contracts(约定)、Services(服务)和Conversation Groups(会话组)。队列队列只是队列。象传统的队列一样,这是先进先出的存储系统。队列提供了在消息发送者和接收者之间的一个连接。消息发送者把消息发送到队列而消息接收者将读取消息。由于消息技术的使用,发送者在发现下一个消息之前不必等待接收者完成消息的处理。发送者可以发送任意数量的消息并且接收者能用不同的速度或者甚至不同的时间去处理它们,从而平均分配资源。在Service Broker里,队列使用隐藏的表。因为消息保持在表里,即使在服务重启之后它们也不会被删除。你也能通过简单的备份数据库来备份消息,因为这些消息是作为数据库的一部分的。另一个重要的特点是你不能对这些消息执行INSERT、DELETE或UPDATE语句。对这些队列只能进行SELECT和RECEVE(这将在本文稍后讨论)操作。消息消息被放到队列中。消息的数据类型是varbinary(max),这是SQLServer2005的一个新的类型。这个新的数据类型让你可以保存最多2GB的消息。你不能通过简单的SELECT语句来查看这些消息。消息总是按照它们发送的顺序接收并保证能到达,因为不管任何原因在发送期间不能丢失。这是MSMQ主要的好处,尽管很多开发者和用户抱怨MSMQ里消息接收和发送的顺序。如果消息由于某种原因没有发送,服务将试图在稍后重新发送,这可以减少你去监控消息。定义一个消息时,你可以定义它包含的消息类型。这向Service Broker消息提供了安全性。确定的类型有EMPTY, WELL_FORMED_XML和VALID_XML_WITH_SCHEMA_COLLECTION。对于EMPTY,你没有在消息上施加任何验证。WELL_FORMED_XML意味着消息要有一个正确的XML格式。VALID_XML_WITH_SCHEMA_COLLECTION和类XmlSchemaCollection是相同的。XmlSchemaCollection是XML-Data Reduced (XDR)和XML Schema Definition (XSD)语言架构能存储和验证的缓存或库。XmlSchemaCollection通过在内存里缓存架构代替从文件或URL访问它们来提升性能。对话你从其他消息应用程序里熟悉了队列和消息。对话是SQLServer2005 ServiceBroker里一个相当新的概念。一些专家也称这为会话。不管什么名字,它是Service Broker的核心。对话是你能放你的消息到队列的一种机制。在对话里,消息按照它们发送的顺序来排序和递送。在正常的环境下,对话被一个特定的任务创建并在用完时被删除。一个对话在两个终端之间发生。终端用来在不同的SQLServer实例的Service Broker进行会话。终端允许Service Broker通过HTTP、TCP、或者SOAP协议进行会话。这些终端缺省地没有配置。所以如果你计划在不同的SQLServer实例之间会话的话,你需要配置它们。Service Broker经常使用端口4022进行会话。如果你需要你可以在创建终端的稍后改变它。约定约定定义了谁能从发起者或接收者那里发送什么类型的消息。在一个约定里你可以指定多个消息类型并指定谁(要么是发起者要么是接收者)能发送。服务服务读取队列里的消息并处理它们。服务可以是SQLServer的存储过程或可以连到对话的不同的程序。会话组当一些消息和其他有关联的时候,会话组将它们联系在一起。如果一个消息处理失败,服务将自动回滚相关的消息处理。Service Broker架构下面是用图形来展示所有的Service Broker的概念和对象:
Source: MSDN
应用程序作为对话的一部分来交换消息。当SQLServer为对话接收到一条消息,它为对话把消息从服务放在队列里。应用程序或者存储过程从队列接收消息并且必要时处理消息。作为处理的一部分,应用程序可以在对话里给其他参与者发送消息。 实践 现在是时候动手操作了。首先,定义一些简单的商业逻辑去验证Service Broker。假定正在设计一个在线购买系统。要求无论何时用户下一订单都要将明细发送给库存系统。从库存系统里,服务将读取一个队列并更新必要的表。(为了简单,假定交易系统和库存系统在一个数据库里。现实是两个系统将在两个不同的服务器上,你必须创建终端去完成会话。)首先创建一个新的数据库叫做SSSB。USE [master]
GO
/****** Object: Database [SSSB] Script Date: 02/19/2007 22:55:11 ******/
IF EXISTS (SELECT name FROM sys.databases WHERE name = N'SSSB')
DROP DATABASE [SSSB]
CREATE DATABASE [SSSB]然后为这个数据库开启Service Broker。ALTER DATABASE [SSSB] SET ENABLE_BROKER现在在库存系统中创建一个订单表。CREATE TABLE [dbo].[tblOrders](
[ID] [int] IDENTITY(1,1) NOT NULL,
[ItemCode] [varchar](15) NULL,
[Qty] [int] NULL,
[OrderDate] [smalldatetime] NULL
CONSTRAINT [PK_tblOrders] PRIMARY KEY CLUSTERED
(
[ID] ASC
)
)必须创建Service Broker对象。首先需要创建一个MESSAGE TYPE和CONTRACT。CREATE MESSAGE TYPE SendStockDetails
VALIDATION = WELL_FORMED_XML;SendStockDetails这个MESSAGE TYPE将发送关于进入库存的消息。当消息假定用XML格式发送时使用WELL_FORMED_XML。
CREATE CONTRACT [MainContract]
(
SendStockDetails SENT BY INITIATOR
);约定指定了这些消息类型用什么方向。下一步是创建队列(queSendStockSend)去发送库存明细。CREATE QUEUE queSendStockSend WITH STATUS= ON, ACTIVATION ( PROCEDURE_NAME = usp_updatetocks,
MAX_QUEUE_READERS = 5, EXECUTE AS 'dbo' ) ;上面的队列有两个主要的参数。一个是存储过程的名称。无论什么时候消息发送给队列,给定的存储过程(usp_updatetocks)将被激活。这个存储过程应在CREATE QUEUE语句之前创建。然而,出于介绍的原因,存储过程将在稍后讨论。另一个参数MAX_QUEUE_READERS指定了队列启动的同时激活存储过程的最大实例数。该值范围在0到32767之间。通过联合队列和约定创建服务。CREATE SERVICE svrStockUpd ON QUEUE queSendStockSend ([MainContract])现在需要写一个存储过程来写数据到队列。该存储过程有两个参数:Itemcode和qty。过程内部,XMLmessage将被格式化后发送给队列。CREATE PROCEDURE [dbo].[usp_StockInfo]
@ItemCode [varchar](15),
@Qty [int]
AS
BEGIN
DECLARE @OrdDate AS SMALLDATETIME
SET @Orddate = GETDATE() -- We assume current date and time as the order date
DECLARE @Message XML
CREATE TABLE #XMLMessage
(
[ItemCode] VARCHAR(15),
[Qty] INT,
[OrderDate] SMALLDATETIME,
)
INSERT INTO #XMLMessage
(
[ItemCode],
[Qty],
[OrderDate]
)
VALUES (
@ItemCode,
@Qty,
@ORddate
)
SELECT @Message = ( SELECT * FROM #XMLMessage
FOR XML PATH('Order'),
TYPE
) ;
-- Above will fomulate valid XML message
DECLARE @Handle UNIQUEIDENTIFIER ;
-- Dialog Conversation starts here
BEGIN DIALOG CONVERSATION @Handle FROM SERVICE svrStockUpd TO
SERVICE 'svrStockUpd' ON CONTRACT [MainContract] WITH ENCRYPTION = OFF ;
SEND ON CONVERSATION @Handle MESSAGE TYPE SendStockDetails (@Message) ;
END
GO你可以观察用于对话会话的服务。消息将使用下面的XML格式:<Order>
<ItemCode>2001</ItemCode>
<Qty>60</Qty>
<OrderDate>2007-02-21T00:32:00</OrderDate>
</Order>首先使用usp_stockinfo写入一些数据[usp_StockInfo] 'A-200',12你会注意到在上面的执行完成后会立即被返回。如果你执行SELECT * FROM dbo.queSendStockSend,你可以看到消息数据。然而,你看到的消息内容是加密了的。(下载上面的示例代码。)接下来需要创建一个存储过程去读取队列。事实上,这应该在队列创建之前创建,因为在创建队列时需要激活存储过程。CREATE PROCEDURE usp_updatetocks
AS
BEGIN
SET NOCOUNT ON ;
DECLARE @Handle UNIQUEIDENTIFIER ;
DECLARE @MessageType SYSNAME ;
DECLARE @Message XML
DECLARE @OrdDate SMALLDATETIME
DECLARE @Qty INT
DECLARE @ItemCode VARCHAR(15) ;
RECEIVE TOP ( 1 )
@Handle = conversation_handle,
@MessageType = message_type_name,
@Message = message_body FROM dbo.queSendStockSend;
IF ( @Handle IS NOT NULL
AND @Message IS NOT NULL
)
BEGIN
SELECT @OrdDate = CAST(CAST(@Message.query('/Order/OrdDate/text()') AS NVARCHAR(MAX)) AS SMALLDATETIME)
SELECT @Qty = CAST(CAST(@Message.query('/Order/Qty/text()') AS NVARCHAR(MAX)) AS INT)
SELECT @ItemCode = CAST(CAST(@Message.query('/Order/ItemCode/text()') AS NVARCHAR(MAX)) AS VARCHAR(15))
INSERT INTO dbo.tblOrders
(
ItemCode,
Qty,
OrderDate
)
VALUES (
@ItemCode,
@Qty,
@OrdDate
) ;
END
END为了读取队列,我们使用了RECEIVE命令。使用RECEIVE命令,你可以在接收队列之后删除队列。如果你使用SELECT,它不会从队列中被移除。由于消息是二进制格式的,我们需要使用CAST函数转换。把它们转换成3个独立的变量然后插入到表里。之后,如果你运行select * from tblOrders,你可能会看到数据已经被Service Broker记录到表tblorder了。在SQLServer2005里使用Service Broker一个为Service Broker提供的典型的例子就是SQLServer2005里数据库邮件。无论何时一个请求的邮件(其实就是Service Broker的内容里的消息)被放入队列,一个外部程序Databasemail90.exe将被Service Broker激活。数据库邮件主要的好处是邮件处理由外部程序完成,这会减少SQLServer的开销。由于Service Broker的架构,这是可以完成的。这里有一些其他你能用到Service Broker好处的地方:- 异步触发器
- 可靠的查询处理
- 可靠的数据收集为客户端提供的分布式服务器端处理
- 为客户端提供的数据合并
- 大规模的批处理
你可以在这里找到所有的细节。结论 SQLServer2005的Service Broker不是为MSMQ的简单的替代品,因为将添加更多有利于系统开发人员的特点。我试着让这篇介绍性的例子简单些。下一篇关于Service Broker的文章将覆盖如安全和终端的高级的特点。
yaozhaosheng - 9/30/2010 3:26:00 AM
很好很强大