0.参考文献:
SQL Server Service Broker MSDN文档总览
SQL Server 2005 Service Broker 初探
1.Service Broker 编程
Service Broker 功能通过 SQL Server 中的新对象启用,这些新对象可以由一组 T-SQL 扩展来创建和操作。为了数据库程序员的方便,使用了他们熟悉的用于配置其他数据库对象的 CREATE、ALTER 和 DROP DDL 语句来配置 Service Broker 应用程序。用于创建 Service Broker 对话以及在对话中发送和接收消息的命令是 Transact SQL 语言的 DML 扩展。接收命令的语法与选择命令相似,它返回包含消息的行集,就像选择命令返回包含行的行集一样。熟悉 Transact SQL 编程的开发人员会发现学习 Service Broker 编程非常容易。用于为 Service Broker 编程的客户端 API 与用于为所有数据库编程的 API 相同,例如 OLEDB、ODBC、ADO、ADO.NET 等等。下面是 Service Broker 使用的对象。
1.1.队列(QUEUE)
Service Broker 使用队列在消息发送程序和消息接收程序之间提供松散耦合。发送程序可以使用 SEND 命令将消息放到队列中,然后应用程序继续操作(不用等待接受程序发送确认回复)并依靠 Service Broker 来确保消息到达其目标位置。
队列允许较大的计划灵活性。例如,发送程序可以发送多条消息以供多个接收程序并行处理。接收程序可能在消息发送很长时间后才处理消息,但由于传入消息进行了排队,因此接收程序可以按其自己的速率处理消息,而且发送程序无须等待接收程序完成处理便可继续操作。
1.2.对话(DIALOG)
Service Broker 还实现了对话,对话是两个端点之间的双向消息流。对话中的所有消息都进行了排序,而且对话消息总是按照发送的顺序传送。该顺序在事务、输入线程、输出线程以及系统崩溃和重新启动过程中都保持不变。
对话是一种会话类型。Service Broker 会话是持久可靠的通信通道。在以后的 SQL Server 版本中,Service Broker 将包括一对多的单向会话,也称为可靠的“发布-订阅”。在 SQL Server 2005 中,对话是唯一的会话类型,因此这两个术语同义。
每条消息都包括唯一标识与它相关的对话的会话句柄。例如,某个订单输入应用程序可能同时使用发货应用程序、库存应用程序和帐单应用程序打开了对话。因为每个应用程序中的消息都具有唯一的会话句柄,所以可以轻松地确定发送每条消息的应用程序。
下面的关系图显示对话的消息流:
1.3.消息类型(MESSAGE TYPE)
当前,所有 Service Broker 消息都与特定的消息类型相关联。消息类型是与消息一起传送的标签,因此接收消息的应用程序可以确定所接收消息的类型。此外,如果消息包含 XML 文档,则消息类型可以与 XML 架构集合相关联。如果为某个消息类型指定了架构集合,则所接收的该类型消息将在收到时根据架构集合进行验证,而没有通过架构验证的消息将会被拒绝。
1.4.规范(CONTRACT)
Service Broker 规范是一个消息类型集合。一个对话总是与一个规范相关联,而规范定义哪些消息类型可以通过对话发送。
1.5.服务(SERVICE)
Service Broker 服务将一个或多个规范与一个队列相关联。规范定义可以将哪些消息类型发送到队列。服务名称用于建立对话的端点。服务名称用作实际队列的别名,因此您可以编写引用服务名称的 Service Broker 程序,然后在部署应用程序时将它与实际队列相关联。
2.Service Broker“Hello World”
大多数编程语言书籍都以“Hello World”示例开始,因此我们也在 Service Broker 中使用 Hello World 作为示例。为简化示例,我使用可以从 SQL Server Management Studio 查询窗口运行的 T-SQL 进行编写。大多数 Service Broker 应用程序将作为普通的数据库应用程序,这些应用程序由通过 ADO 或 ADO.NET 与数据库进行通信的可执行程序和使用 T-SQL 或 .NET 语言编写的 SQL Server 存储过程构成。
要发送和接收消息,必须首先创建向 Service Broker 描述应用程序的消息传送部分的元数据对象。在 SQL Server 2005 中,使用新添加的 DDL 语句来创建、修改和删除 Service Broker 元数据。
代码示例
-- step1 -- 创建要使用的数据库 Create Database HelloWorldDB go Use HelloWorldDB go --step2 /*创建要使用的两种消息类型。我们要使用的消息将是 字符串而不是 XML,因此无需进行验证 */ CREATE MESSAGE TYPE [HelloWorldRequest] VALIDATION = NONE CREATE MESSAGE TYPE [HelloWorldResponse] VALIDATION = NONE --step3: /*创建一个限制此对话框中消息类型的规范。 请求由对话框的初始化程序发出响应消息由对话框目标发送。 */ CREATE CONTRACT [HelloWorldContract] ( [HelloWorldRequest] SENT BY initiator, [HelloWorldResponse] SENT BY target ) --step4 -- 创建对话框在其间通信的两个队列。A对话框请求两个队列。 CREATE QUEUE [HelloWorldTargetQueue] CREATE QUEUE [HelloWorldInitiatorQueue] --step5 -- 创建命名对话框端点的服务。服务会将会话端点连接到队列。 CREATE SERVICE [HelloWorldRequestService] ON QUEUE [HelloWorldTargetQueue] ( [HelloWorldContract] ) CREATE SERVICE [HelloWorldResponseService] ON QUEUE [HelloWorldInitiatorQueue] go --step6 /*现在已经设置了元数据,可以发送消息了。请注意,由于初始化程序和目标服务 位于同一 SQL Server 实例中,因此消息将直接转到目标队列而不会通过传送队 列传送。由于 Service Broker 内置在数据库中,因此可以进行此项性能优化。 */ SET NOCOUNT ON DECLARE @conversationHandle uniqueidentifier Begin Transaction--事物开始 -- 开始 Hello World 服务的对话 BEGIN DIALOG @conversationHandle FROM SERVICE [HelloWorldResponseService] TO SERVICE 'HelloWorldRequestService' ON CONTRACT [HelloWorldContract] WITH ENCRYPTION = OFF, LIFETIME = 600; -- 发送消息 SEND ON CONVERSATION @conversationHandle MESSAGE TYPE [HelloWorldRequest] (N'Hello World') commit--事物提交 --step7 --让我们查看目标队列以确保成功发送了消息。检查目标队列以确认消息已送达 select * from [HelloWorldTargetQueue] go -- 将消息主体转换为字符串,以便我们查看其中包含的内容 select cast(message_body as nvarchar(MAX)) from [HelloWorldTargetQueue] go --step8 /*现在可以从目标队列中接收消息并将响应发送回初始化程序。使用 Receive 命令可从队列接收消息 */ -- 声明变量以存储接收到的数据 SET NOCOUNT ON DECLARE @conversationHandle uniqueidentifier --对话的标识符 declare @message_body nvarchar(MAX)--消息体 declare @message_type_name sysname;--消息类型名称 -- Service Broker 命令总是位于事务中 Begin Transaction; -- Receive 命令的格式类似于一个选择列表。首先列出要获取的列, -- 然后指定要从中获取消息的队列 RECEIVE top(1) -- 只接收一条消息,因此我们可以直接保存到变量中。 @message_type_name=message_type_name, -- 接收的消息类型 @conversationHandle=conversation_handle, -- 对话的标识符,我们通过下列语句接收该消息 @message_body=message_body -- 作为varbinary(MAX) blob 的消息内容 FROM [HelloWorldTargetQueue] print @message_body -- 如果这是一条 hello world 消息,则用相应的问候语回答 if @message_type_name = N'HelloWorldRequest' Begin SEND ON CONVERSATION @conversationHandle MESSAGE TYPE [HelloWorldResponse] (N'Hello From '+@@servername ) -- 这是我们希望从初始化程序接收的唯一消息,因此现在可以安全地结束对话。 END CONVERSATION @conversationHandle End -- 提交事务 -- 如果此时我们回滚,所有内容将退回到 -- 我们开始时的状态 – 消息会返回到队列,并且没有发送响应 Commit go --step9 -- 确认我们从队列中删除了消息 select cast(message_body as nvarchar(MAX)) from [HelloWorldTargetQueue] go --step10 --响应已在对话中发送回初始化程序队列,现在检查响应是否成功到达: select cast(message_body as nvarchar(MAX)) from [HelloWorldInitiatorQueue] go --step11 -- 最后接收并显示响应消息: RECEIVE cast(message_body as nvarchar(MAX)) FROM [HelloWorldInitiatorQueue]
执行上述代码以后,我们可以查看SSMS中HelloWorldDB的Servic Broker属性,如下图所示,主要列出了我们创建的队列、服务等信息: