科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航



ZDNet>软件频道>数据库-zhiding>如何在SQL Server 2005中使用Service Broker内部激活

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

在本文中,我将带领你建立一个小型的Service Broker应用程序,它使用内部激活(Internal Activation)来处理所提交的消息。

来源: 2007年03月02日

关键字:SQL Server SQL Server 2005 SQL Server 2005 SQLServer Tim Chapman

在前面的文章中,我说明了基于消息的系统背后的理论,并介绍了Service Broker组件——在数据库引擎中建立异步消息应用程序的SQL Server 2005新特性。在本文中,我将带领你建立一个小型的Service Broker应用程序,它使用内部激活(Internal Activation)来处理所提交的消息。

内部激活

在举例之前,我想提及一下Service Broker应用程序中的内部激活功能。在许多情况下,消息一到达队列就对它们进行处理,这种做法是合适的。在Service Broker应用程序中,你可以指定一个存储过程,只要有消息到达一个队列,就立即执行它。在某种程度上,它就像队列中的异步触发器。

使用这种技巧的优点在于,如果你的队列由于收到大量消息而陷入困境,你可以对队列进行设置,使它启动更多存储过程实例。我认为这是Service Broker应用程序的一项非常重要的功能,因此我将在下面的例子中分析内部激活的运行机制。

实例

这个例子说明如何调用一个提交Service Broker消息的存储过程,它反过来调用一个存储过程来处理第一个存储过程提交的消息。

USE master

GO

IF EXISTS(SELECT * FROM sys.databases where name = 'SB')

DROP DATABASE SB

GO

CREATE DATABASE SB

GO

ALTER DATABASE SB

SET ENABLE_BROKER

GO

上面的脚本用来建立这个例子使用的数据库环境。在我能够应用其功能之前,我首先必须在数据库中启动Service Broker;ENABLE_BROKER语句帮助我启动它。

下面的脚本建立一个Sales表,我在整个实例中都要用到它。

USE SB;

GO

CREATE TABLE Sales

(

SaleID INT IDENTITY(1,1),

SaleDate SMALLDATETIME,

SaleAmount MONEY,

ItemsSold INT

);

GO

为建立所需的Service Broker组件,我创建了MESSAGE TYPE和CONTRACT对象。MESSAGE TYPE对象确认消息的内容,它对会话获得的消息实行严格控制。CONTRACT对象指定所用到的MESSAGE TYPE对象,以及会话中消息的传送方向。

CREATE MESSAGE TYPE [RecordSale] VALIDATION = NONE;

CREATE CONTRACT [SalesContract]

(

[RecordSale] SENT BY INITIATOR

);

GO

这个应用程序将消息从一个Service Broker队列传递给另一个队列,因此我需要建立实现这些功能的脚本。首先,我建立SalesQueue,它将接收消息,并启动一个过程来处理它们。(SalesService处理进入的消息并把它们传递给SalesQueue。)

CREATE QUEUE [SalesQueue];

CREATE SERVICE [SalesService] ON QUEUE [SalesQueue]([SalesContract]);

GO

点击查看更多数据库技术文章
http://soft.zdnet.com.cn/software_zone/db.shtml

列表A中的脚本建立我用作激活过程的存储过程。每次有消息到达SalesQueue队列时,就调用这个过程。

在这个过程中,我使用新的TSQL结构RECEIVE从SalesQueue队列中提取消息。(RECEIVE非常类似于SELECT语句,不同之处在于RECEIVE从队列中提取消息。)如果你需要查看消息的内容,但并不移动它们,你可以在队列上运行SELECT语句,就像在表中一样。

当我从队列收到一条消息时,我把来自队列的域值保存在当地变量中。我对@Message变更特别感兴趣,它将保存我提交到队列的XML文件。因为消息的正文以XML保存,我可以使用XQuery语句从XML文件中提取数据。我提取的数据是我提交到最初过程的变量。一旦我“切碎”了XML数据,我只需简单把这些值插入Sales表中。

既然我计划给SalesService服务发送消息,我需要一个发送消息的服务和队列。下面的语句建立RecordSalesQueue和RecordSalesService队列,后者被附加到RecordSalesQueue上。

CREATE QUEUE [RecordSalesQueue];

CREATE SERVICE [RecordSalesService] ON QUEUE [RecordSalesQueue];

GO

当你对一个Service Broker队列使用内部激活时,你需要启动内部激活并指定你将调用的存储过程。我最初建立SalesQueue时没有启动它,因此现在我必须启动它。这个操作用ALTER QUEUE语句来完成,如下:

ALTER QUEUE [SalesQueue] WITH ACTIVATION

(

STATUS = ON,

MAX_QUEUE_READERS = 1,

PROCEDURE_NAME = usp_RecordSaleMessage,

EXECUTE AS OWNER

);

GO

列表B中的脚本建立我在输入销售信息时将要用到的过程。我将保持简化,因此我仅向过程提交三个变量(尽管这不是一个很大的交易,但如有必要,可以提交更多变量)。

在这个过程中,你会注意到,我把提交到过程的参数插入到一个临时表中;然后我查询临时表,把结果集放到一个XML变量中。这种方法可以方便地把你的数据格式化成XML,而不用动态建立一个XML字符串。

实际上,BEGIN DIALOG CONVERSATION处理从RecordSalesService向SalesService提交消息的过程。这个语句返回一个会话句柄,你可以使用它来发送消息。SEND ON CONVERSATION语句执行发送XML消息的工作,SELECT语句从临时表中建立这个XML消息。

现在,我已经为激活过程做好准备,只等消息到达。要看它如何运行,执行下面的存储过程:

EXECUTE usp_SendSalesInfo '1/9/2005',30,90

执行这个过程后,运行下面的SELECT语句看Sales表中是否插入一条记录。

SELECT * FROM Sales;

内部激活的优点

我可能会看着上面的例子,心里想:“这有什么好处?不过是往表中增加一条记录而已!”在这种情况下,这是一个合理的问题。但是,不要遗漏这个例子背后的理念。

消息应用程序的目的是帮助你发送一条消息,并继续进行你的工作。在上面的例子中,如果从触发器中调用usp_SendSalesInfo存储过程,就需要在触发器下次激活前插入记录。如果触发器要完成许多处理工作,这肯定会造成系统瓶颈。但是,如果你只使用存储过程向队列传送消息,触发器就可以迅速地完成处理工作,而且可以在后台完成这些工作。

Tim Chapman是肯塔基州路易维尔市一家银行的SQL Server数据库管理员,他有超过7年的IT行业经验。他还通过了微软SQL Server 2000和SQL Server 2005的认证。

责任编辑:德东

查看本文国际来源

CREATE PROCEDURE usp_RecordSaleMessage
AS
BEGIN

            SET NOCOUNT ON;
            DECLARE @Handle UNIQUEIDENTIFIER;
            DECLARE @MessageType SYSNAME;
            DECLARE @Message XML
            DECLARE @SaleDate DATETIME
            DECLARE @SaleAmount MONEY
            DECLARE @ItemsSold INT;

     
            RECEIVE TOP (1)
                  @Handle = conversation_handle,
                  @MessageType = message_type_name,
                  @Message = message_body
            FROM [SalesQueue];
           
               
            IF(@Handle IS NOT NULL AND @Message IS NOT NULL)
            BEGIN
                  SELECT @SaleDate = CAST(CAST(@Message.query('/Params/SaleDate/text()') AS NVARCHAR(MAX)) AS DATETIME)
                  SELECT @SaleAmount = CAST(CAST(@Message.query('/Params/SaleAmount/text()') AS NVARCHAR(MAX)) AS MONEY)
                  SELECT @ItemsSold = CAST(CAST(@Message.query('/Params/ItemsSold/text()') AS NVARCHAR(MAX)) AS INT)

                  INSERT INTO Sales(SaleDate ,SaleAmount ,ItemsSold )
                  VALUES(@SaleDate,@SaleAmount,@ItemsSold);
            END
END
GO
CREATE PROCEDURE usp_SendSalesInfo
(
      @SaleDate SMALLDATETIME,
      @SaleAmount MONEY,
      @ItemsSold INT
)
AS
BEGIN

      DECLARE @MessageBody XML
      CREATE TABLE #ProcParams
      (
            SaleDate SMALLDATETIME,
            SaleAmount MONEY,
            ItemsSold INT
      )
      INSERT INTO #ProcParams(SaleDate,SaleAmount, ItemsSold)
      VALUES(@SaleDate, @SaleAmount, @ItemsSold)

      SELECT @MessageBody = (SELECT * FROM #ProcParams FOR XML PATH ('Params'), TYPE);

      DECLARE @Handle UNIQUEIDENTIFIER;

      BEGIN DIALOG CONVERSATION @Handle
      FROM SERVICE [RecordSalesService]
      TO SERVICE 'SalesService'
      ON CONTRACT [SalesContract]
      WITH ENCRYPTION = OFF;

      SEND ON CONVERSATION @Handle
      MESSAGE TYPE [RecordSale](@MessageBody);
END
GO
推广二维码
邮件订阅

如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

重磅专题