第8章 ADO基础
在本书前7章中,已经讲述了ASP的有关内容,以及ASP如何为Web站点带来动态的内容。已经见到其脚本程序允许自定义Web页面,使我们能够构建功能更为强大的ASP页面。
现在,将研究ASP和数据的集成。虽然对用于网页中的脚本数量并无任何限制,但如果没有某种形式的数据,很快就会进入一个死胡同。数据构成了Web站点的实际内容,或者指出了如何设置Web站点,因此总的说来数据是非常重要的。如果围绕数据存储建立Web站点,改变Web站点时只需要改变相应的数据即可。
ActiveX数据对象(ADO)是允许用户与数据存储进行交互的组件。这意味着只要基于某些数据就可建立一个网页,或一种完全交互的电子商务系统。不论哪种方式,都是ADO使我们能与数据进行通信。我们将讨论从数据存储获取和传送数据的主要内容,以及得到数据后的数据处理方法。
首先研究什么是ADO及其所包括的组件,然后讨论如何访问数据存储。在下一章,将进一步学习ADO更先进的一些特性,如命令、存储过程和优化应用程序的一些操作技巧。下一步研究Web服务器和浏览器之间的交互过程,以及数据处理过程。然后研究数据存取领域中极具潜力的XML。XML是什么?如何使用?因为XML代表着未来发展的一种趋势,我们将介绍微软关于通用数据存取的构想。在这个构想中,数据不只是从数据库中获得的。最后,看一下标准的微软数据库(如Access与SQL Server)以及在其中如何使用ADO。
本章从ADO开始,主要内容有:
· 研究ADO如何与数据进行交互。
· 了解ADO的组件。
· 如何与数据存储连接和创建数据集。
· 如何处理和修改数据。
· 如何处理ADO错误。
8.1 ADO的定义
ADO是一个相当简单的思想,一种让你仅用一种方式去访问数据的思想。ADO不算一个新思想,仅是采用现有的数据库访问技术,并将其融合而形成的一种适应现在和未来需要的新东西。适应未来的需求是一件十分重要的事。许多其他的技术,比如DAO和ODBC,在一些应用程序的开发过程中是可以接受的,然而随着Internet的兴起也出现了其自身的一些问题。
在许多情况下,传统的数据存取方法看上去能解决一些关于两层客户/服务器系统的问题,但要求与数据之间要保持一种永久性的连接,并要提供强大的功能,比如快速响应的查询、数据容易修改等。在Internet领域,现在必须考虑到Web无状态性本质,和潜在的众多可以访问Web站点的用户。要与数据建立永久的连接是不现实的,因此必须在设计应用程序时考虑这些因素。
那么,OLD DB和ADO确切地讲到底是什么?让我们与一些已有的数据存取技术做比较后再来回答这个问题。如果读者曾经接触过数据库编程,或许比较熟悉ODBC和RDO。开放数据库连接(ODBC)是允许访问关系数据库(比如Access和SQL Server)的应用程序编程接口(API)。正因为是一个API,许多程序员,特别是Visual Basic领域的程序员,发现它使用起来很复杂。远程数据对象(RDO)是位于ODBC上层的ActiveX对象,可以提供ODBC的所有功能,并且使用起来比较简单。
可以将OLE DB等同于ODBC,ADO等同于RDO。
OLE DB是应用程序与数据源交互的一种基本技术。
这相当复杂,确实也只有C和C++程序员能够使用。正如ADO的名字所暗示的,它是易于访问OLE DB功能的ActiveX对象。
你或许发现术语ActiveX与COM对象经常混用。对于ASP程序员来说它们并没有本质上的区别,因为两者都基于COM系统结构,只不过ActiveX是组件的一个跨平台标准,而COM是Windows专有的。
虽然微软已经引入了一种新的存取数据的技术,但并没有立即取消旧的技术,ODBC工作起来仍然很有效,并同OLE DB和ADO紧密地一起工作着。事实上,ODBC并不只是微软的产品,也受到国际组件的控制。并且由于广泛的使用,ODBC也不会突然消亡。隐藏在OLE DB背后的思想不是摒弃现有的技术,而是不断地改进它们。
8.1.1 OLE DB和ADO的体系结构
前面已经给出了OLE DB与ADO在一些主要方面的简要解释。图8-1显示了这两项技术与应用程序和数据存储相互关系:
图8-1 OLE DB、ADO与应用程序和数据存储的关系
从图8-1中可以看出整体思路。图的顶端是应用程序(Web或常规的应用程序,这是无关紧要的),下面是提供对数据的访问的ADO和/或OLE DB。ADO和OLE DB两者兼有是因为OLE DB是一项基本技术。然而,OLE DB并不适用于所有语言,所以ADO位于OLE DB的上层,为那些不能直接访问OLE DB的语言(如Visual Basic和脚本语言)提供编程接口。ADO提供了比OLE DB更容易的编程接口,因此即使那些可以直接使用OLE DB的编程语言,如C++或Java,也可使用ADO以简化对数据的访问。
图8-1显示的是微软的编程语言,而ADO是一个COM组件,因此可用于任何与COM兼容的编程语言,比如Delphi或支持Active Scripting接口的脚本语言。所以,虽然ADO与平台有关,但与开发的语言是无关的。当然,对于ASP主要使用VBScript和JScript,在组件中使用ADO时,有一些Visual Basic代码。
现在知道了OLE DB和ADO允许访问数据,可是为什么需要它们?老方法出问题了吗?这里有两个主要原因:
首先,OLE DB和ADO是用来访问数据存储的。注意这里指“数据存储”而不是“数据库”。尽管数据库仍旧是数据存储最为广泛的形式,但并不一定含有全部的数据。一些消息系统,如Microsoft Exchange Server,也普遍地用于存储数据。目录服务(Directory Service)正开始在初露端倪,它们包含着有关用户、机器等的数据;Web服务器中存有大量的信息。可以继续罗列下去,很明显需要一种能访问所有这些不同类型数据的方法。
其次,源于Internet应用程序的兴起与Web的状态本质。过去的访问数据的方法主要考虑与数据存储保持永久连接的情况下处理数据。而OLE DB和ADO正是为解决这个问题而设计的,提供断开连接的记录集,我们将会在后面看到有关这方面的内容。
8.1.2 消费者与提供者
ADO系统结构图展示了ADO是如何在应用程序和真实数据存储之间发挥作用的。在微软的文献中,会看到两个易懂的术语:消费者(Consumer)和提供者(Provider),但搞清它们的确切定义至关重要。
提供者是提供数据的物体,消费者是使用(消耗)这些数据的物体。
在编程中,经常会发现应用程序是数据的消费者。但提供者呢?一般是数据存储,并且由于OLE DB被设计成用于与不同的数据存储对话,因此对于每一个独特类型的数据存储都有一个OLE DB提供者。
这种单独提供者的思想并不新,但使编程变得容易了。编写程序与ADO或OLE DB对话,OLE DB再与提供者对话。这意味着只需学会一套访问数据的方法,无论数据如何存储,在某些情况下确实可以完全不改变任何代码而只更换提供者。这就是ADO和OLE DB真正优越的地方,为数据存储提供了一套常用的编程接口。
要连接到数据存储,必须使用OLE DB提供者。提供给ADO 2.5的初始设置为:
· Jet OLE DB 4.0:用于微软Access数据库。
· DTS Packages:用于SQL Server的数据转换服务(Data Transformation Services)。
· Internet Publishing:用于访问Web服务器。
· Indexing Services:用于索引目录(Index Catalogs)。
· Site Server Search:用于站点服务器查找目录。
· ODBC Drivers:用于ODBC数据源。
· OLAP Services:用于微软OLAP服务器。
· Oracle:用于Oracle数据库。
· SQL Server:用于微软SQL Server数据库。
· Simple Provider:用于简单的文本文件。
· MSDataShape:用于层次数据。
· Microsoft Directory Services:用于Windows 2000的目录服务。
· DTS Flat File:用于SQL Server的数据转换服务的平面文件管理。
这只是微软提供的初始列表,并取决于安装在服务器上的服务及软件。以Oracle数据提供者为例,要求在客户机上安装Oracle的客户端软件。
可以从别的制造商那里获得OLE DB提供者,用于其他数据存储。甚至还可以编写自己的提供者。在第11章,将演示如何编写简单的OLE DB提供者。
要想知道系统安装了哪些提供者,可以使用Data Link properties对话框。在本章后面,将介绍如何使用它。
8.1.3 提供者和驱动程序
值得注意的是,OLE DB对ODBC的兼容性,允许OLE DB访问现有的ODBC数据源。其优点很明显,由于ODBC相对OLE DB来说使用得更为普遍,因此可以获得的ODBC驱动程序相应地要比OLE DB的要多。这样不一定要得到OLE DB的驱动程序,就可以立即访问原有的数据系统。
避免混淆提供者与驱动程序是重要的,图8-2明确了它们之间的区别:
图8-2 提供者与驱动程序之间的区别
提供者位于OLE DB层,而驱动程序位于ODBC层。如果想使用一个ODBC数据源,需要使用针对ODBC的OLE DB提供者,它会接着使用相应的ODBC驱动程序。如果不需要使用ODBC数据源,那么可以使用相应的OLE DB提供者,这些通常称为本地提供者(native provider)。
可以清楚地看出使用ODBC提供者意味着需要一个额外的层。因此,当访问相同的数据时,针对ODBC的OLE DB提供者可能会比本地的OLE DB提供者的速度慢一些。
8.2 ADO 2.5对象模型
虽然在ADO 2.5对象模型中出现了两个新对象,但与以前的版本基本上是类似的。图8-3显示了这些对象以及每个对象之间的关系:
图8-3 对象之间的相互关系
如果以前使用过ADO,你会发现在这个新版本中出现了两个新对象:Stream和Record对象。在第11、12章将详细介绍它们。
Properties集合已经被有意地排除在图8-3外,这样你对几个主要对象之间的交互关系就一目了然了。在本章的后面,有显示Properties集合的简化对象模型。
让我们更详细地考察这几个对象。
8.2.1 Connection对象
Connection对象是使我们能与数据存储相连的对象。只有Connection对象才能指定希望使用的OLE DB提供者、连接到数据存储的安全细节以及其他任何连接到数据存储特有的细节。
应用注意的是,不必显式创建一个Connection对象以连接到数据存储。尽管确实需要指定连接细节,但没有Connection对象,一样可以创建Command、Recordset和Record对象。如果不创建自己的Connection对象,ADO将会隐含地为你创建一个Connection对象。如果要对提供者运行多条命令,应该显式地创建一个Connection对象,这比每运行一条命令就创建一个连接更有效。
除了为数据存储提供连接以外,Connection对象允许针对数据存储执行命令操作。这些命令可以是结构化的或存储的命令(例如,SQL命令或一个存储过程),并且可以有选择地从数据存储中返回一些数据。
8.2.2 Command对象
Command对象是对数据存储执行命令的对象。看到这里读者可能会产生疑问,Connection对象不也能这样做吗?是的,但是Connection对象在处理命令的功能上受到一定的限制,而Command对象是特别为处理命令的各方面问题而创建的。实际上,当从Connection对象中运行一条命令时,已经隐含地创建一个Command对象。
有时其他对象允许向命令传入参数,但在Connection对象中不能指定参数的任何细节。使用Command对象允许指定参数(以及输出参数和命令执行后的返回值)的精确细节(比如,数据类型和长度)。
因此,除了执行命令和得到一系列返回记录,也可能得到一些由命令提供的附加信息。
对于那些不返回任何记录的命令,如插入新数据或更新数据的SQL查询,Command对象也是有用的。
8.2.3 Recordset对象
Recordset对象是ADO中使用最为普遍的对象,因为它含有从数据存储中提取的数据集。我们经常运行不返回数据的命令,比如那些增加或更新数据的命令,但在大多数情况下很有可能会取得一系列记录。
Recordset对象是拥有这些记录的对象。可以更改(增加、更新和删除)记录集中的记录,上下移动记录,过滤记录并只显示部分内容等等。Recordset对象也包含Fields集合,Fields集合中有记录集中每一个字段(列)的Filed对象。
无论是在ASP页面中处理数据,还是利用远程数据服务(RDS)远程使用数据,Recordset对象是必须处理的对象。
8.2.4 Record对象
ADO 2.5以前的版本在处理结构化数据上是很有效的,比如从数据库中取出记录集,但无法处理每一行的列(也就是列数和数据类型)可能不同的数据。对于SQL数据这不是一个问题,但对于文件和邮件系统,Web服务器和别的诸如此类的数据存储会如何呢?我们把这些数据看作是半结构化的数据,与记录集相比结构性较差,但与那些常用来代表文本或图像的二进制数据相比更具有结构性。
通常,半结构化数据的存储采用树状结构来组织,有节点、子节点和文件。例如,设想一个有文件夹、子文件夹和文件的Web站点。图8-4所示的屏幕图显示了一台机器的Web站点,特别是还有一个名为public的虚拟目录:
图8-4 显示了一台机器的Web站点的界面
如果一定要在ADO中进行建模,会觉得这非常适合记录集,可能是嵌套的记录集。然而注意高亮度显示的目录,该目录含有不同类型的文件,里面有几个目录、两个ASP文件、一个文本文件和一个WORD文档。你会很容易地将其映射到一个拥有名称、类型、上次存取时间等字段的记录集,遗憾的是并不是这样简单。对于访问权限而言,在文件和目录之间就有区别。对于目录,需要的是能访问目录下的文件;而对于文件,却可能是需要访问其内容。
由于其复杂性,引入了Record对象。在上面的情况下,存在有一些相同属性的条目的一个集合,但是每个条目也有独特的属性,因此需要使用别的方法去处理这些数据。把一个集合映射到一个记录集,一个单独的文件映射成一条记录,相应的文件属性就映射成Fields集合。
这意味着有了一个含有六行记录的记录集。访问记录集中单独的一行就会得到该文件的属性(字段),但是提供给我们的仅仅是属性,为了访问文件或目录的内容,需要使用Record对象,该对象包含文件或目录的独特属性。习惯于这个概念有一定的困难,但不必担心,在第11、12章你会看到更多有关Record对象的例子。 Windows 2000初始版本发布以来,只有用于Internet发布的OLE DB提供者使用Record对象。一旦微软Exchange 6.0发布,将成为以类似方法利用记录集和记录提供对Exchange信息库访问的OLE DB提供者。