在SQL Server 2005中,Microsoft引进了一个令人振奋的新特性即服务代理(Service Broker),同时这也给许多数据库管理人员带来了一个新的概念。这个概念,进程外消息,是一个开发人员在一些产品中使用多年的应用,如Microsoft Message Queue (MSMQ)。实现这个功能,需要运行一个SQL Server命令,并且对该命令的数据进行处理。但是,因为用户不需要命令的输出,因此它不需要立刻进行处理。这里就是消息队列发挥作用地方。
正常情况下,当用户在SQL Server中启动存储过程时,他们必须等待存储过程完成数据处理,然后再进行下一个动作。通过使用服务代理,他们可以让实际数据处理排队等候一下。在这种情况下,用户将运行存储过程而非数据处理。我们将输入数据打包作为一个消息,然后将消息发到队列去。我们配置队列自动读取信息,并处理信息中的数据。
ON QUEUE [tcp://SearchSQLServer/SampleQueue]
(
[tcp://SearchSQLServer/SampleContract]
)
消息可以在同一个数据库中发送,可以在一个服务器上的一个数据库发送到另一个数据库,或在服务器之间包括因特网上的服务器之间发送。这个过程就如同邮件一样。当我给我的朋友发一封邮件,他接收到邮件之后可以进行读取(信息处理),接着可以就根据内容做点什么。服务代理就是以这样的方式运作的。
设置服务代理发送和接收消息的四个步骤:
在实际发送和接收消息之前,服务代理有几个组件需要配置。比如,我们将消息输入一个队列来作自动处理。这些消息的处理可以是自动的,或者是某个Windows应用所需要的,或者队列中读取消息的服务。
与其它对象一样,服务代理名称在数据库中必须是唯一的。然而,如果准备在服务器之间发送消息,那么在设置服务代理对象名称时,就必须加倍细心。一般情况下,我们都推荐将系统名称和功能名称组合起来作为服务代理对象名称。这样可以确保在整个企业中,对象名称都是唯一的。当在内部使用了服务代理的系统之间发送消息并且想要避免对象命名问题时,你会发现这样做是非常方便的。可以使用UNC形式名称来保证唯一性。比如,我们将从tcp://SearchSQLServer/开始对象的命名。
1、第一步需要在服务代理中设置的对象是消息类型,它告诉SQL Server消息的基本信息。服务代理消息可以是任意数据类型:文本、二进制、XML、数据等等。推荐使用的是XML,因为它可以包含其它任意数据类型。我们使用CREATE MESSAGE TYPE命令来创建消息类型。其中有四个验证选项。如果想要执行有效的XML格式化,可以选择WELL_FORMED_XML或VALID_XML WITH SCHEMA COLLECTION(使用一个XSD来执行XML模式)。
dbo
VALIDATION = NONE
2、下一步我们需要配置的对象是契约(Contract)。它告诉SQL Server哪些消息类型是相关的。我个人倾向于在一个特定进程中对所有的通信使用一个的消息类型,以保持简单。然而,Microsoft SQL Server Books OnLine的例子在发送系统使用一个消息类型,而接收系统使用另一个类型。
(
[tcp://SearchSQLServer/SampleMessageType] SENT BY ANY
)
3、现在让我们来看看服务代理上的实际队列。这个队列有点像一个表格。在这里存储了等待处理的的消息。与表格不一样的是,你无法定义队列的模式。因此,推荐使用XML来发送,这样你才可以在XML中来定义模式。
下一个服务代理的配置对象是服务。服务是服务代理用来在数据库中消息传送到正确的队列,同时将契约绑定到队列消息中。
4、最后一个对象是路由,但它是可选的。路由只有在数据库服务器之间发送消息时才是必须的。路由与接收消息服务的本地副本器密不可分。如果服务器接收的消息是另外一个使用数据库镜像的服务器的镜像,那么就必须使用一个MIRROR_ADDRESS参数。如果想让路由自动删除,那么可以设置LIFETIME标志。
WITH SERVICE_NAME = '[tcp://SearchSQLServer/SampleService]',
BROKER_INSTANCE = 'AB2F3EB9-6662-4AAF-8682-A9A48C3BDD3B',
ADDRESS = 'TCP://RemoteServer:8888',
MIRROR_ADDRESS = 'TCP://MirrorServer:8888'
BROKER_INSTANCE参数是service_broker_guid字段的值,它来自远程服务器上的数据库的sys.databases视图。
为了实现队列之间的消息发送,必须使用两个命令。第一个是BEGIN DIALOG命令,然后是SEND命令。使用BEGIN DIALOG命令在发送和接收服务器之间来创建一个会话。如果使用一个已有的会话,那么就不需要使用BEGIN DIALOG命令。在使用BEGIN DIALOG命令创建了新的会话之后,就可以用SEND命令在会话上发送消息,其中消息的发送是通过BEGIN DIALOG命令返回的句柄实现。
@XMLData XML ;
SET @XMLData = (SELECT * FROM sys.tables FOR XML AUTO)
BEGIN DIALOG @dialog_handle
FROM SERVICE [tcp://SearchSQLServer/SampleService]
TO SERVICE 'tcp://SearchSQLServer/SampleService'
ON CONTRACT [tcp://SearchSQLServer/SampleContract];
SEND ON CONVERSATION @dialog_handle
MESSAGE TYPE [tcp://SearchSQLServer/SampleMessageType]
(@XMLData);
RECEIVE命令是用来查看和处理消息。RECEIVE命令与SELECT非常相似,都会返回数据。但是,当使用RECEIVE命令时,消息只能接收一次。在消息接收之后,如果它是会话中最后的消息——很多人都只在会话中输入一个消息,那么就使用END CONVERSATION命令来关闭它。RECEIVE命令可以与WAITFOR 命令一起使用,而WHILE循环用来处理程序的一次运行中的队列上的所有消息。
@XMLData XML ;
RECEIVE TOP (1) @dialog_handle = conversation_handle, @XMLData =
CAST(message_body AS XML)
FROM [tcp://SearchSQLServer/SampleQueue]
END CONVERSATION @dialog_handle
SELECT @XMLData
结束会话时,事实接收队列会发送一个消息到发送队列,以此来通知发送队列、服务和SQL Server,会话结束了。这个结束会话消息必须由发送队列处理以便
将数据从队列中删除。建议在发送队列上使用基本程序来自动清除这些消息。
AS
DECLARE @xml AS XML
DECLARE @dialog_handle as uniqueidentifier
WHILE 1=1
SET @dialog_handle = NULL
WAITFOR ( RECEIVE TOP (1) @dialog_handle = conversation_handle, @xml =
cast(message_body as xml)
FROM [tcp://SearchSQLServer/SampleQueue]), TIMEOUT 1000
IF @dialog_handle IS NULL
break
END CONVERSATION @dialog_handle
END
GO
完成这个程序之后,当消息到达时,可以通过QUEUE的ACTIVATION命令来使用ALTER QUEUE命令设置一个队列自动地运行该程序。你可以设置程序的并行执行数目,将MAX_QUEUE_READERS设置为大于1。在高负荷的系统中,或当处理花费一定时间时,附加队列读取器可以通过并行方式加速数据处理。
WITH ACTIVATION (STATUS=ON,
PROCEDURE_NAME = dbo.usp_ProcessAck,
MAX_QUEUE_READERS = 2,
EXECUTE AS SELF)
SQL Server Service Broker的安装可能有点复杂,并且在因特网上相关的文档也不是很多。但是,一旦安装并正确运行了服务代理,它可以提供一个坚如磐石的内部或外部数据库通信平台,实现系统之间数据的快速一致发送。