创建与执行Data Transformation Services (DTS)

在微软的SQL Server 2000中,您可以使用Web与数据转移服务(Data Transformation Services (DTS))软件包将数据库事件扩展到应用软件,这篇文章将为您演示如何在SQL Server 2000中创建与执行Data Transformation Services (DTS)。

多数情况下,任何数据的改变都存在于应用程序中。在应用系统中,程序通过交互对事件产生响应,然而,除非您的程序存在于系统当中,否则系统生成的事件对于外部程序是不可见的。

将一个外部程序绑定到系统中去消费这些事件往往包括了很多老式的重体力劳动和一些运气,在当今的离线系统中,越来越多的程序需要对系统事件做出响应,而同时又要与产生事件的系统保持分离。大多数系统负责操作数据以及改变数据库中保存的数据,触发器用于捕获这些改变并对数据库做出相应的操作,然而,如果能将这些事件扩展到外部世界将是一件美好的事,在微软的SQL Server 2000中,您可以使用Web与数据转移服务(DTS)软件包来扩展这些数据库事件到外部程序中。

在这篇文章中,我将使用一个存储过程(stored procedure)来执行一个DTS软件包,它们将依次执行ActiveX脚本来向Web服务发送请求,这些Web服务将负责协调所生成的事件的处理工作。

SQL Server 2000中创建DTS软件包

通常,当设计一个系统的时候,您需要考虑将自己的系统连接到外部系统的所有可能性,然而,您可以结束这场关于如何处理事件的拉锯战:您是否通过服务来查询状态,或您是否希望外部系统可以接受您生成的事件?如果您的程序是一个负责操作与移动数据的商业软件,那么最好将创建事件的工作留给产生数据改动的数据库,这些改动可以通过表格触发器来实现,新的事件可以通过事件的订阅者来发布。

在SQL Server 2000中,您可以创建一个DTS软件包,它将执行ActiveX脚本,该脚本只是一个简单的VBScript文件,当然,这个VBScript文件包含了一些特定的关于DTS执行的知识,这些特定知识包括可进行条件操作的全程变量,而这些条件操作正是基于变量所存储的信息,使用CreateObject语句,脚本就可以创建一个MSXML2.ServerXMLHTTP组件的实例,该组件提供了生成HTTP请求的能力,在此,DTS软件包可以向Web服务甚至最简单的网页发出请求来推动一个事件,然后,该服务或Web程序可以通过执行必需的操作来处理该“事件”,从而实现了该请求的操作。

现在您需要一个从T-SQL中帮助执行DTS软件包的方法,为了封装这一功能,存储过程是一个理想的选择,在存储过程中,您可能需要可执行文件dtsrun来运行DTS包,使用xp_cmdshell的系统存储过程,您就可以像执行命令行程序一样运行dtsrun,有一些命令行参数可以帮助您成功运行dtsrun.EXE,我使用以下这些参数:

  • /S—识别SQL实例的服务器名称
  • /E—在当前下对已登录用户使用信任安全
  • /N—执行的DTS软件包的名称
  • /M—DTS的执行密码(如果设定过)
  • /A—传递到DTS软件包的全程变量的名称、类型和数值

您的存储过程应该通过执行xp_cmdshell的系统存储过程来执行DTS软件包,该命令可以将命令行字符串作为参数使用,为建立这样的字符串,您的存储过程应该可以接受变量信息最为参数;在这种情况下,存储过程将调用命令行解释程序来接受服务器名称、DTS软件包名称、DTS密码和全程变量,全程变量应当使用"VariableName":"datatypeid"="value"这种形式来传递,所以一个对存储过程的DTS调用的应该看上去是这样的:

dtsrun /S (local) /E /N MyPackage /M dtspassword /A "variable1":"8"="some string"

建立这条命令行字符串的过程显示在列表A,这将有效建立命令行字符串,其中包含的全程变量可以通过@GlobalVariableList来设定,然后,就可以通过xp_cmdshell系统存储过程在命令行参数下执行dtsrun.EXE,最后,如果有错误的话,它将返回一个错误代码。

列表A

CREATE Procedure DtsRunTrusted

@ServerNamevarchar(30),

@DtsPkgNamevarchar(30),

@DtsPasswordvarchar(30),

@GlobalVariableListvarchar(1000)

AS

DECLARE @err int

DECLARE @cmdvarchar(1000)

BEGIN

SET @err = 0

IF( @GlobalVariableList IS NULL )

BEGIN

SET @cmd = 'dtsrun /S '+@ServerName+' /E /N '+@DtsPkgName+' /M

'+@DtsPassword

END

ELSE

BEGIN

SET @cmd = 'dtsrun /S '+@ServerName+' /E /N '+@DtsPkgName+' /M

'+@DtsPassword+' '+@GlobalVariableList+''

END

EXECUTE @err = master..xp_cmdshell @cmd

SELECT @err = COALESCE(NULLIF(@err, 0), @@ERROR)

IF @err <> 0 RETURN @err

END

SQL Server 2000中执行DTS软件包

现在您可以执行DTS软件包了,但仍然需要一个DTS软件包来执行,创建DTS包的最简单的方法是使用SQL企业管理器中的DTS包设计器,可按照以下步骤操作:

  • 使用设计器创建一个新的包
  • 添加一个名称为eventId的整数型全程变量,并将其值设定为0
  • 添加一个ActiveX脚本任务并将以下代码加到脚本中:

Function Main()

Dim oXmlHttp As Object

Set oXmlHttp = CreateObject("MSXML2.ServerXMLHTTP.3.0");

oXmlHttp.open "POST",

"http://localhost/DotNet/WebServices/EventService.asmx/NewEvent", False

oXmlHttp.setRequestHeader "Content-Type", "application/x-www-form

-urlencoded"

oXmlHttp.send "eventId=" & DTSGlobalVariables("eventId").Value

Set oXmlHttp = Nothing

Main = DTSTaskExecResult_Success

End Function

创建Web服务来接收生成的事件

您可以将事件生成服务的订阅者添加到数据库的表中,然后,名为DtsRunTrusted的存储过程可以收集订阅了事件的使用者的URL,并将URL传递到DTS软件包中作为一个全程变量,然后向该订阅者发送一个HTTP的请求。

在我的例子中,我只打算含有一个事件使用者,但对于多个订阅者,将负责异步操作的ServerXMLHTTP对象设为True是个更明智的做法,这样做不会让您的Web服务速度减慢,而且事件也可以按照实时方式生成。

ASP.NETWeb服务中使用数据库事件

使用这种数据库事件非常简单,事件ID可以与事件表相关联,而这些事件包含了关于系统的更详细的信息,同时还要牢记,存储在事件表中的信息应当提供有效的信息,并且对于外部程序而言是足够抽象的,从而外部程序可以使用系统内的信息。

列表B包含了一个ASP.NET的Web服务的框架代码,该Web服务将负责处理事件,这里需要注意的一点是NewEvent方法被定义为一个WebMethod,该方法可以接收一个参数:eventId,在这个方法内,您可以添加代码来处理生成的事件。

现在您可以创建以数据为中心的应用软件了,而且还可以按照您的需求添加过程模块,您对数据的任何改变都可以创建事件通知,并将这些通知发送给需要信息的程序,然后这些程序就可以按照需要处理数据的改变。

列表B

using System;

using System.Collections;

using System.ComponentModel;

using System.Data;

using System.Diagnostics;

using System.Web;

using System.WebServices;

using System.Net;

namespace WebServices

{

public class EventService : System.Web.Services.WebService

{

public EventService()

{

InitializeComponent();

}

private IContainer components = null;

private void InitializeComponent()

{

}

protected override void Dispose( bool disposing )

{

if (disposing && components != null)

{

components.Dispose();

}

base.Dispose(disposing);

}

[WebMethod]

public void NewEvent(inteventId)

{

//TODO: Handle event.

}

}

}

posted on 2007-01-18 15:34  吴磊  阅读(1212)  评论(0编辑  收藏  举报