80
最 新 评 论
80
专 题 分 类
80
最 新 日 志
80
最 新 留 言
80
搜 索
用 户 登 录
友 情 连 接
我 的 好 友
80
博 客 信 息
80


WINDOWS环境下数据库访问技术 | 2010/1/10 20:07:00
        当前,在WINDOS环境下访问数据库服务器的主流标准接口有ODBC、OLE DB和ADO。下面分别对这三种接口进行概要介绍:

1、开放数据库连接(ODBC)

ODBC

  ODBC(Open Database Connectivity,开放数据库互连)是微软公司开放服务结构(WOSA,Windows Open Services Architecture)中有关数据库的一个组成部分,它建立了一组规范,并提供了一组对数据库访问的标准API(应用程序编程接口)。这些API利用SQL来完成其大部分任务。ODBC本身也提供了对SQL语言的支持,用户可以直接将SQL语句送给ODBC。
  一个基于ODBC的应用程序对数据库的操作不依赖任何DBMS,不直接与DBMS打交道,所有的数据库操作由对应的DBMS的ODBC驱动程序完成。也就是说,不论是FoxPro、Access , MYSQL还是Oracle数据库,均可用ODBC API进行访问。由此可见,ODBC的最大优点是能以统一的方式处理所有的数据库。
  一个完整的ODBC由下列几个部件组成:
  应用程序(Application)。
  ODBC管理器(Administrator)。该程序位于Windows 95控制面板(Control Panel)的32位ODBC内,其主要任务是管理安装的ODBC驱动程序和管理数据源。
  驱动程序管理器(Driver Manager)。驱动程序管理器包含在ODBC32.DLL中,对用户是透明的。其任务是管理ODBC驱动程序,是ODBC中最重要的部件。
  ODBC API。
  ODBC 驱动程序。是一些DLL,提供了ODBC和数据库之间的接口。
  数据源。数据源包含了数据库位置和数据库类型等信息,实际上是一种数据连接的抽象。
  各部件之间的关系如图下图所示:
  应用程序要访问一个数据库,首先必须用ODBC管理器注册一个数据源,管理器根据数据源提供的数据库位置、数据库类型及ODBC驱动程序等信息,建立起ODBC与具体数据库的联系。这样,只要应用程序将数据源名提供给ODBC,ODBC就能建立起与相应数据库的连接。
  在ODBC中,ODBC API不能直接访问数据库,必须通过驱动程序管理器与数据库交换信息。驱动程序管理器负责将应用程序对ODBC API的调用传递给正确的驱动程序,而驱动程序在执行完相应的操作后,将结果通过驱动程序管理器返回给应用程序。
  在访问ODBC数据源时需要ODBC驱动程序的支持。用Visual C++ 5.0安装程序可以安装SQL Server、 Access、 Paradox、 dBase、 FoxPro、 Excel、 Oracle 和Microsoft Text等驱动程序.在缺省情况下,VC5.0只会安装SQL Server、 Access、 FoxPro和dBase的驱动程序.如果用户需要安装别的驱动程序,则需要重新运行VC 5.0的安装程序并选择所需的驱动程序。
  ODBC 使用层次的方法来管理数据库,在数据库通信结构的每一层,对可能出现依赖数据库产品自身特性的地方,ODBC 都引入一个公共接口以解决潜在的不一致性,从而很好地解决了基于数据库系统应用程序的相对独立性,这也是ODBC 一经推出就获得巨大成功的重要原因之一。
  从结构上分,ODBC 分为单束式和多束式两类。
  1.单束式驱动程序
  单束式驱动程序介于应用程序和数据库之间,像中介驱动程序一样数据提供一个统一的数据访问方式。当用户进行数据库操作时,应用程序传递一个ODBC 函数调用给ODBC 驱动程序管理器,由ODBC API 判断该调用是由它直接处理并将结果返回还是送交驱动程序执行并将结果返回。由上可见,单束式驱动程序本身是一个数据库引擎,由它直接可完成对数据库的操作,尽管该数据库可能位于网络的任何地方。
  2.多束式驱动程序
  多束式驱动程序负责在数据库引擎和客户应用程序之间传送命令和数据,它本身并不执行数据处理操作而用于远程操作的网络通信协议的一个界面。前端应用程序提出对数据库处理的请求,该请求转给ODBC 驱动程序管理器,驱动程序管理器依据请求的情况,就地完成或传给多束驱动程序,多束式驱动程序将请求翻译为特定厂家的数据库通信接口(如Oracle 的SQLNet)所能理解的形式并交于接口去处理,接口把请求经网络传送给服务器上的数据引擎,服务器处理完后把结果发回给数据库通信接口,数据库接口将结果传给多束式ODBC 驱动程序,再由驱动程序将结果传给应用程序。

2、OLE DB

OLE DB

  OLE DB(OLEDB)是微软的战略性的通向不同的数据源的低级应用程序接口。OLE DB不仅包括微软资助的标准数据接口开放数据库连通性(ODBC)的结构化查询语言(SQL)能力,还具有面向其他非SQL数据类型的通路。 作为微软的组件对象模型(COM)的一种设计,OLE DB是一组读写数据的方法(在过去可能被称为渠道)。OLE DB中的对象主要包括数据源对象、阶段对象、命令对象和行组对象。使用OLE DB的应用程序会用到如下的请求序列: 初始化OLE 连接到数据源、发出命令、处理结果、释放数据源对象并停止初始化OLE
  Object Linking and Embedding,对象连接与嵌入,简称OLE技术。OLE不仅是桌面应用程序集成,而且还定义和实现了一种允许应用程序作为软件“对象”(数据集合和操作数据的函数)彼此进行“连接”的机制,这种连接机制和协议称为部件对象模型。
  OLE 是一种面向对象的技术,利用这种技术可开发可重复使用的软件组件(COM)。
  DB(英文全称data base,数据库)是依照某种数据模型组织起来并存放二级存储器中的数据集合。
  OLE DB 标准中定义的新概念
  OLE DB 将传统的数据库系统划分为多个逻辑组件,这些组件之间相对独立又相互通信。这种组件模型中的各个部分被冠以不同的名称:
  数据提供者(Data Provider)。提供数据存储的软件组件,小到普通的文本文件、大到主机上的复杂数据库,或者电子邮件存储,都是数据提供者的例子。有的文档把这些软件组件的开发商也称为数据提供者。
  数据服务提供者(Data Service Provider)。位于数据提供者之上、从过去的数据库管理系统中分离出来、独立运行的功能组件,例如查询处理器和游标引擎(Cursor Engine),这些组件使得数据提供者提供的数据以表状数据(Tabular Data)的形式向外表示(不管真实的物理数据是如何组织和存储的),并实现数据的查询和修改功能。SQL Server 7.0 的查询处理程序就是这种组件的典型例子。
  业务组件(Business Component)。利用数据服务提供者、专门完成某种特定业务信息处理、可以重用的功能组件。分布式数据库应用系统中的中间层(Middle-Tier)就是这种组件的典型例子。
  数据消费者(Data Consumer)。任何需要访问数据的系统程序或应用程序,除了典型的数据库应用程序之外,还包括需要访问各种数据源的开发工具或语言。
  OLE DB 与ODBC 的关系
  由于OLE DB 和ODBC 标准都是为了提供统一的访问数据接口,所以曾经有人疑惑:OLE DB 是不是替代ODBC 的新标准?答案是否定的。实际上,ODBC 标准的对象是基于SQL 的数据源(SQL-Based Data Source),而OLE DB 的对象则是范围更为广泛的任何数据存储。从这个意义上说,符合ODBC 标准的数据源是符合OLE DB 标准的数据存储的子集。符合ODBC 标准的数据源要符合OLE DB 标准,还必须提供相应的OLE DB 服务程序(Service Provider),就像SQL Server 要符合ODBC 标准,必须提供SQL Server ODBC 驱动程序一样。现在,微软自己已经为所有的ODBC 数据源提供了一个统一的OLE DB 服务程序,叫做ODBC OLE DB Provider。
  ODBC OLE DB Provider 发布之后,有人又担心:ODBC Provider 是不是在ODBC 之上的新的层次(Layer)?如果是,那么使用OLE DB 访问ODBC 数据源是否将影响性能?答案也是否定的。实际上,ODBC Provider 的作用,是替换ODBC Driver Manager,作为应用程序与ODBC 驱动程序之间的桥梁,理论上不会增加任何开销。


3、动态数据库对象(ADO)

概述

微软公司的ADO (ActiveX Data Objects) 是一个用于存取数据源的COM组件。它提供了编程语言和统一数据访问方式OLE DB的一个中间层。允许开发人员编写访问数据的代码而不用关心数据库是如何实现的,而只用关心到数据库的连接。访问数据库的时候,关于SQL的知识不是必要的,但是特定数据库支持的SQL命令仍可以通过ADO中的命令对象来执行。ADO被设计来继承微软早期的数据访问对象层,包括RDO (Remote Data Objects) 和DAO(Data Access Objects)。ADO在1996年冬被发布。

ADO 对象总结  (1)ADO包含一些顶层的对象:
  连接,代表到数据库的连接
  记录集,代表数据库记录的一个集合
  命令,代表一个SQL命令
  记录,代表数据的一个集合
  流,代表数据的顺序集合
  错误,代表数据库访问中产生的意外
  字段,代表一个数据库字段
  参数,代表一个SQL参数
  属性,保存对象的信息
  ADO组件的使用需要利用支持COM的高级语言,例如ASP中的VBScript或者Visual Basic,甚至Delphi,微软的竞争对手Borland的一个产品,现在也支持使用ADO来访问数据库。
  在新的编程框架.NET Framework中, 微软也提供了一个面向Internet的版本的ADO,称为ADO.NET。其对象模型和传统ADO差别很大。 ADO是一种面向对象的编程接口,微软介绍说,与其同IBM和Oracle提倡的那样,创建一个统一数据库,不如提供一个能够访问不同数据库的统一接口,这样会更加实用一些。为实现这一目标,微软在数据库和微软的OLE DB中提供了一种“桥”程序,这种程序能够提供对数据库的连接。 开发人员在使用ADO时,其实就是在使用OLE DB,不过OLE DB更加接近底层。ADO的一项属性远程数据服务,支持“数据仓库”ActiveX 组件以及高效的客户端缓存。作为ActiveX的一部分,ADO也是COM组件的一部分。ADO是由早期的微软数据接口??远程数据对象RDO演化而来的。RDO同微软的ODBC一同连接关系数据库,不过不能连接非关系数据库。
  ADO向我们提供了一个熟悉的,高层的对OLE DB的Automation封装接口。对那些熟悉RDO的程序员来说,你可以把OLE DB比作是ODBC驱动程序。如同RDO对象是ODBC驱动程序接口一样,ADO对象是OLE DB的接口;如同不同的数据库系统需要它们自己的ODBC驱动程序一样,不同的数据源要求它们自己的OLE DB提供者(OLE DB provider)。目前,虽然OLE DB提供者比较少,但微软正积极推广该技术,并打算用OLE DB取代ODBC。
  ADO向VB程序员提供了很多好处。包括易于使用,熟悉的界面,高速度以及较低的内存占用(已实现ADO2.0的Msado15.dll需要占用342K内存,比RDO的Msrdo20.dll的368K略小,大约是DAO3.5的Dao350.dll所占内存的60%)。同传统的数据对象层次(DAO和RDO)不同,ADO可以独立创建。因此你可以只创建一个"Connection"对象,但是可以有多个,独立的"Recordset"对象来使用它。ADO针对客户/服务器以及WEB应用程序作了优化。
  ADO (ActiveX Data Objects,ActiveX数据对象)是Microsoft提出的应用程序接口(API)用以实现访问关系或非关系数据库中的数据。例如,如果您希望编写应用程序从DB2或Oracle数据库中向网页提供数据,可以将ADO程序包括在作为活动服务器页(ASP)的HTML文件中。当用户从网站请求网页时,返回的网页也包括了数据中的相应数据,这些是由于使用了ADO代码的结果。
  象Microsoft的其它系统接口一样,ADO是面向对象的。它是Microsoft全局数据访问(UDA)的一部分,Microsoft认为与其自己创建一个数据,不如利用UDA访问已有的数据库。为达到这一目的,Microsoft和其它数据库公司在它们的数据库和Microsoft的OLE数据库之间提供了一个“桥”程序,OLE数据库已经在使用ADO技术。ADO的一个特征(称为远程数据服务)支持网页中的数据相关的ActiveX控件和有效的客户端缓冲。作为ActiveX的一部分,ADO也是Microsoft的组件对象模式(COM)的一部分,它的面向组件的框架用以将程序组装在一起。
  ADO从原来的Microsoft数据接口远程数据对象(RDO)而来。RDO与ODBC一起工作访问关系数据库,但不能访问如ISAM和VSAM的非关系数据库。
  ADO 是对当前微软所支持的数据库进行操作的最有效和最简单直接的方法,它是一种功能强大的数据访问编程模式,从而使得大部分数据源可编程的属性得以直接扩展到你的Active Server 页面上。可以使用ADO 去编写紧凑简明的脚本以便连接到 Open Database Connectivity (ODBC) 兼容的数据库和 OLE DB 兼容的数据源,这样 ASP 程序员就可以访问任何与 ODBC 兼容的数据库,包括 MS SQL SERVER、Access、 Oracle 等等。
  比如,如果网站开发人员需要让用户通过访问网页来获得存在于IBM DB2或者Oracle数据库中的数据,那么就可以在ASP页面中包含ADO程序,用来连接数据库。于是,当用户在网站上浏览网页时,返回的网页将会包含从数据库中获取的数据。而这些数据都是由ADO代码做到的。
  ADO是一种面向对象的编程接口,微软介绍说,与其同IBM和Oracle提倡的那样,创建一个统一数据库,不如提供一个能够访问不同数据库的统一接口,这样会更加实用一些。为实现这一目标,微软在数据库和微软的OLE DB中提供了一种“桥”程序,这种程序能够提供对数据库的连接。 开发人员在使用ADO时,其实就是在使用OLE DB,不过OLE DB更加接近底层。ADO的一项属性??远程数据服务,支持“数据仓库”ActiveX 组件以及高效的客户端缓存。作为ActiveX的一部分,ADO也是COM组件的一部分。ADO是由早期的微软数据接口??远程数据对象RDO演化而来的。RDO同微软的ODBC一同连接关系数据库,不过不能连接非关系数据库。

ADO下载

  目前ADO1.5版已经可以从微软网站免费下载。到目前为止,微软网站仍是你获取有关ADO最新信息的最佳场所。ADO1.5是作为OLE DB SDK的一部分提供的。
  在下载之前请先确认OLE DB SDK提供的各项特性。下载文件大约有15M,如果完全安装的话要占用80M的硬盘空间。如果你只对ADO感举趣,就选择最小安装,这样只会占用你15M的硬盘空间。
  在这里你可以找到许多关于ADO的示例代码和文章,尤其是在"Workshop"系列的文章中。你也可以从本站下载ADO2.5的帮助文件。
  尽管OLE DB SDK提供自己的ADO帮助文件,你会发现ADO1.0的帮助文件更易于使用。同时它还向你提供ADO对象模型的图示

ADO是如何组织起来的?

  以前的对象模型,如DAO和RDO是层次型的。也就是说一个较低的数据对象如Recordset是几个较高层次的对象,如Environment和QueryDef,的子对象。在创建一个QueryDef对象的实例之前,你不能创建DAO Recordset对象的实例。但ADO却不同,它定义了一组平面型顶级对象.
  最重要的三个ADO对象是Connection, Recordset和Command. 本文将主要介绍Connection和Recordset这两个对象。每个Connection的属性定义了与数据源的连接。Recordset对象接收来自数据源的数据。Recordset可以与Connection一起起使用,先建立一个连接,然后获取数据。尽管如此,Recordset也可以被单独创建,其Connection参数可以在Open属性定义。

ADO 2.0特点

  对于ADO1.5以前包括1.5的版本来说,从功能的角度来看RDO和ADO不是完全相等的.等同就意味着你可以通过这两种方法解决同样的问题;它不是指存在重命名的或者优化的功能相同的对象.因此,移植到ADO 不是一个简单的事情.从另一方面来说,一旦你熟练掌握了RDO或DAO技术的话,学习ADO是件相当容易的事情.
  ADO 2.0的新特性包括事件处理,记录集的延续,分层目录结构指针和数据成形,分布式事务处理,多维数据,远程数据服务(RDS),以及对C++和Java的支持的增强.在钻研一些Visual Basic代码的时候将会见到所有的这些特性.当使用Visual J++时,我将举例说明新的Windows Foundation Classes(WFC)是如何支持ADO的.ADO的最让人激动的是在Visual Studio 6.0中的任何开发工具中你都可以找到对它的充分的支持.

ADO 对象编程模型

  连接数据源 (Connection),可选择开始事务。
  可选择创建表示 SQL 命令的对象 (Command)。
  可选择指定列、表以及 SQL 命令中的值作为变量参数 (Parameter)。
  执行命令(Command、Connection 或 Recordset)。
  如果命令以行返回,将行存储在存储对象中 (Recordset)。
  可选择创建存储对象的视图以便进行排序、筛选和定位数据 (Recordset)。
  编辑数据。可以添加、删除或更改行、列 (Recordset)。
  在适当情况下,可以使用存储对象中的变更对数据源进行更新 (Recordset)。
  在使用事务之后,可以接受或拒绝在事务中所做的更改。结束事务 (Connection)。

ADO使用方法

  一旦安装了ADO,在VB的工程->引用对话框中你就可以看到象下图所示的东西了:
  选择 "ActiveX Data Objects 1.5 Library" (ADODB).在其下的 "ADO Recordset 1.5 Library"是一个客户端的版本(ADOR),它定义了有聚的数据访问对象。ADOR 对于客户端的数据访问来说是足够的了,因为你不需要Connection对象来建立与远程数据源的联系。
  如果你想要访问更多的外部数据源,你需要安装这些外部数据源自己的OLE DB Provider,就象你需要为新的数据库系统安装新的ODBC驱动程序一样。如果该外部数据源没有自己的OLE DB Provider,你就得使用OLE DB SDK来自己为这个外部数据源创建一个OLE DB Provider了。这已不是本文讨论的范围了。
  示例
  下面的示例代码以Northwinds数据库作为远程数据源,然后用ADO来访问它。首先在控制面板中打开“32位数据源”,单击“添加”按钮。在弹出的对话框中选择 "Microsoft Access Driver (*.mdb)" 作为数据源驱动程序。
  然后按下图所示,在对话框中填写下面的内容
  选择数据库Northwinds所在路径。单击完成,退出ODBC设备管理器。
  启动一个新的VB工程,在窗体的Load事件中输入下面的代码:
  Private Sub Form_Load()
  Dim cn As ADODB.Connection
  Set cn = New ADODB.Connection
  'Set Connection properties
  cn.ConnectionString = "DSN=RDC Nwind;UID=;PWD=;"
  cn.ConnectionTimeout = 30
  cn.Open
  If cn.State = adStateOpen Then _
  MsgBox "Connection to NorthWind Successful!"
  cn.Close
  End Sub
  按F5运行程序,看看,一个消息框弹出来告诉你连接成功了。请注意,这里我特别注明了是ADODB.Connection,而不是ADOR.Connection,这样做是为了将二者区分开(如果你引用了ADODB和ADOR的话,这样做很有必要)。连接字符串看上去同RDO的连接字符串差不多。事实上,二者确实差不多。
  如果我们要访问一个SQL server数据库,你的Connection代码看上去应象下面所示:
  '设置连接属性cn.Provider = "MSDASQL"
  cn.ConnectionString = "driver={SQL Server};" & "server=prod1;uid=bg;pwd=;database=main"
  cn.Open
  "Provider"属性指向SQL Server的OLE DB Provider.
  回到我们的示例程序,让我们创建一个Recordset对象来访问“Orders”表,并从该表的"ShipCountry"字段中产生头十个不重复的国家名。修改窗体Load事件中的代码,让它看上去象下面这样。
  Private Sub Form_Load()
  Dim cn As ADODB.Connection
  Dim rs As ADODB.Recordset
  Dim sSQL As String
  Dim sOut As String
  Dim Count As Integer
  Set cn = New ADODB.Connection
  Set rs = New ADODB.Recordset
  ' Set properties of the Connection.
  cn.ConnectionString = "DSN=RDC Nwind;UID=;PWD=;"
  cn.ConnectionTimeout = 30
  cn.Open
  If cn.State = adStateOpen Then _
  MsgBox "Connection to NorthWind Successful!"
  sSQL = "SELECT DISTINCT Orders.ShipCountry FROM Orders"
  Set rs = cn.Execute(sSQL)
  'Enumerate the recordset
  sOut = ""
  For Count = 1 To 10
  sOut = sOut & rs("ShipCountry") & vbCrLf
  rs.MoveNext
  Next Count
  MsgBox sOut, vbExclamation, "ADO Results"
  cn.Close
  End Sub
  运行程序后,你会看到如下图所示的消息框。
  不幸的是,目前这个Recrodset对象是只读的和forward cursor。如果你想要获取更多的功能,你需要创建一个独立的Recordset对象,该对象拥有自己的Connection属性,就象下面的代码所示:
  Private Sub Form_Load()
  Dim rs As ADODB.Recordset
  Dim sSQL As String
  Dim sOut As String
  Dim Count As Integer
  Set rs = New ADODB.Recordset
  sSQL = "SELECT DISTINCT Orders.ShipCountry FROM Orders"
  rs.Open sSQL, "DSN=RDC Nwind;UID=;PWD=;", adOpenDynamic
  'Report Recordset Connection information
  MsgBox rs.ActiveConnection, , "Connection Info"
  'Enumerate the recordset
  sOut = ""
  For Count = 1 To 10
  sOut = sOut & rs("ShipCountry") & vbCrLf
  rs.MoveNext
  Next Count
  MsgBox sOut, vbExclamation, "ADO Results"
  rs.Close
  End Sub
  上面代码返回的结果同前例一样,但是本代码中的Recordset是独立的。这一点是DAO和RDO做不到的。Recordset对象的Open方法打开一个代表从SQL查询返回的记录的游标。虽然你可以用Connection对象同远程数据源建立连接,但请记住,在这种情况下,Connection对象和Recordset对象是平行的关系。
  总结
  本文仅向你介绍了ADO强大的功能的冰山一角。微软承诺,在将来ADO将会取代DAO和RDO。所以现在你应该考虑如何将你的数据访问代码投向ADO的怀抱。这种转变不会很痛苦,因为ADO的语法同现有的语法差不多。也许微软或第三方会在将来开发出转换向导来简化这一转换过程。从现在起,你就应开发纯ADO代码的程序。你也可以继续使用DAO或RDO代码来开发你的程序,但落伍的感觉总是不好的。

ADO编程应用

  ADO(ActiveX Data Objects)是基于组件的数据库编程接口,它是一个和编程语言无关的COM组件系统。本文主要介绍用ADO编程所需要注意的技巧和在VC下进行ADO 编程的模式,并对C++Extensions进行了简单的讨论,希望对ADO开发人员有一定的帮助作用。因为ADO是一个和编程语言无关的COM组件系统,所以这里讨论的要点适用于所有的编程语言和编程环境,比如:VB、VBScript、VC、Java等等。
  1.显式定义对象类型
  实际上,这条准则不仅适用于ADO编程,也适用于其他的与COM对象相关的编程。因为如果一开始就定义变量类型,则编译器在编译的时候就可以知道变量的类型,此时编译器实际上是采用vtable偏移的方式来得到具体的COM对象包含的方法的地址(这一点和 C++中虚函数的地址获取方式类似);但如果一开始不指定变量类型的话,比如简单地采用如下的语句:
  DIM myCon as Object
  或者是:
  DIM myCon
  这样,编译器在编译的时候就不能得到变量的类型,而只能在运行的时候动态地得到方法的信息(通过使用接口IDispatch的Invoke方法来实现),如此为了得到方法的地址和相关的变量情况就需要在内部进行两次调用,无疑会降低程序的运行速度。
  2.绑定列到具体的字段对象
  在程序开始时就建立对字段对象的引用,可以避免在每次得到记录后,再在Recordset::Fields中进行查找而增加系统的开销。
  例如,可以采用如下所示的代码:
  Private Sub TblBrowse_Click()
  Dim fld1 As ADODB.Field
  Dim fld2 As ADODB.Field
  Dim rs As ADODB.Recordset
  set rs=g_cn.execute(...)
  'g_cn为全局对象adodb.connection
  Set fld1 = rs.Fields(“id”) '数据表的字段
  Set fld2 = rs.Fields(“name”) ’数据表的字段
  If rs.BOF = False Then
  While rs.BOF = False
  Debug.Print fld1.Value
  Debug.Print fld2.Value
  rs.MoveNext
  Wend
  End If
  rs.Close
  End Sub
  3.用SQL语句和存储过程进行数据更新
  尽管采用Recordset对象来更新数据是非常方便的,但是它的开销也大,通过数据源对象返回的查询集不仅包含了数据,而且也包含了元数据(metadata), 在有些时候元数据可能比数据本身还要大,所以最好采用SQL语句来更新数据。还有要使用存储过程而不是单一的SQL语句来获取信息。因为存储过程是在服务器端执行的,只把结果返回到客户端,这样一方面可以降低网络进行数据交互的开销,另一方面使系统更加容易维护,并且能保持数据的一致性。
  4.使用集合操作单条的SELECT语句
  在使用游标时,最好使用集合的方法对单条的SELECT语句进行操作。Recordset:: get_Collect方法和Recordset::put_Collect方法是Recordset 对象的快捷方式,可以快速地得到一个字段的值而不需要获得关于一个字段的引用。例如,可以采用如下代码:
  Sub Collect()
  Dim rs As New Recordset
  rs.ActiveConnection = “...”
  rs.Source=“一条SQL查询语句”
  rs.Open
  Debug.Print rs.Collect(0),rs.Collect(1),rs.Collect(2)
  Debug.Print rs!au_id, rs!au_fname, rs!au_lname
  End Sub
  5.只查询所需要的数据
  尽管很多开发人员都习惯采用“SELECT * FROM TBL”的模式进行查询,但是为了提高系统的效率,如果只需要其中某几个字段的值,最好把这几个字段直接写出来,同时需要限定返回记录集的范围(通过WHERE子句进行限定)。
  6.正确选择游标的位置、类型和锁方式
  如果只需要按顺序读取记录并且不需要滚动和更新记录,最好使用服务器端游标(adUseServer)、仅向前游标(adOpenForwardOnly)和读加锁(adLockReadOnly),这样可以获得最好的性能。如果需要滚动记录,采用客户端游标(adUseServer)会比采用服务器端游标所得到的性能要好,因为ADO系统默认是采用服务器端游标类型。当然如果数据集合相当大,采用服务器端游标的性能会好一些。同时需要注意:如果采用客户端游标,最好只采用读加锁(adLockReadOnly)的锁类型,因为如果需要更新数据,客户端游标引擎需要得到额外的信息(元数据),而获取这个信息的代价是非常昂贵的。
  7.调整记录集对象的CacheSize属性
  ADO使用记录集对象的CacheSize属性来决定提取和缓存的记录的数目,当在缓存的范围内浏览数据时,ADO就只从缓存中提取数据。当要浏览的数据超出缓存范围的时候,ADO就释放当前缓存,提取下一些记录(提取的数目为CacheSize所指定的大小),所以必须根据具体的应用程序的情况,来设定CacheSize的大小,保证得到最佳的性能。
  8.定义Command对象的参数
  在许多数据源中,得到参数信息和执行命令的代价几乎是一样的,所以最好自己在程序中定义好Command参数(也就是说要定义好参数的名称、类型和方向信息),避免一些从数据提供者(Provider)那里获取信息的操作。
  9.使用原始的OLE DB提供者
  MDAC对许多数据源提供了原始的数据提供者,比如SQL Server、Oracle和Access数据库,这样就不需要再通过ODBC来获取数据(也就是说不需要再通过ODBC驱动这一层),这样的好处是能更快地得到数据,并且能降低磁盘和内存的开销。
  10.断开Connection连接
  如果使用客户端游标,就要断开Connection连接。ADO有一个特征是当使用客户端游标操作 Recordset记录集的时候,不需要和服务器保持联系。所以可以充分利用这个特性降低服务器端的开销(服务器就不需要维护这些连接了)。当操作完记录集需要更新时,可以重新和数据库进行连接来更新数据。为了创建一个可以断开连接的记录集,同时需要使用静态游标(adOpenStatic)和批处理的加锁模式(adLockBatchOptimistic)。下面是有关处理的VC代码:
  pRs.CreateInstance(__uuid(Recordset));
  pRs->CursorLoction=adUseClient;
  pRs->Open(strCmdText,strConnection,adOpenStatic,adLockBatchOptimistic,adCmdText);
  pRs->PutRefActiveConnection(NULL);
  //对记录集对象pRs进行操作
  //重新和数据库建立连接
  pRs->PutRefActiveConnectio(pCon);
  //批量更新数据
  pRs->UpdateBatch(adAffectAll);
  需要注意的是:当执行批量更新时,必须自己处理数据冲突问题,因为更新数据时,其他用户也可能同时正在对该数据进行操作。
  11.使用adExecuteNoRecords选项
  如果不需要返回记录,要使用adExecuteNoRecords选项。ADO 2.0包括一个新的执行选项称为adExecuteNoRecords。当使用该选项的时候,ADO就不会创建记录集对象,不设置任何游标属性。数据提供者因为不需要认证集合的属性而使性能得到优化。具体的例子如下:
  con.Execute “insert into tbl values(fv1, fv2) ”, , adExecuteNoRecords
  对仅有一条的执行语句采用Connection::Execute方法比使用Recordset::Open方法或者是Command::Execute方法的效果要好,因为ADO不保留任何命令状态的信息,因此执行性能就有所改进。
  12.使用session/connection缓冲池
  因为数据库的打开和关闭非常消耗系统资源,因此,使用连接池对基于多层的应用的性能会有很大的提高。当使用MDAC的时候,开发人员本身并不需要考虑对数据库连接的缓存,MDAC会自动处理它。连接池在两个层次上提供支持:OLE DB sessions和ODBC连接。如果使用ADO,数据库连接会自动被OLE DB session缓冲池所缓存;如果使用ODBC,可以利用在ODBC数据源管理中新的连接缓冲池选项对ODBC缓冲进行设置。
  实现方法
  我们知道,在VB下进行基于ADO的编程相对比较简单,只要通过reference加载了适当的类型库后,就可以正常地调用ADO对象。但是对于VC下的基于ADO的数据库开发就稍微复杂一些。VC中实现对ADO操作通常有三种方法:
  #import方法;
  利用MFC OLE的ClassWizard;
  通过Windows API中COM相关的函数。
  在这三种方法中,#import是最方便的方法,它允许产生一个类似VB的类结构,使程序开发变得很方便。下面分别介绍这三种方法。
  1.#import方法
  在#import方法中,需要提供所要包含的类型库的路径和名称,VC能够自动产生一个对GUIDs的定义,以及自动生成对ADO对象的封装。对任何引用的类型库,VC会在编译的时候自动生成两个文件:
  头文件(.tlh):包含了所列举的类型和对类型库中对象的定义;
  实现文件(.tli):对类型库对象模型中的方法产生封装。
  例如,在stdafx.h文件中增加对msado15.dd的
  #import之后,VC会产生msado15.tlh和msado15.tli两个文件。
  #import能够使用一个新的类_com_ptr_t,它也被称为智能指针。智能指针能够自动执行QuyerInterface、AddRef和Release函数。
  下面的代码演示了如何使用#import在应用中实现对ADO的操作:
  #import “c:\program files\common files\system\ado\msado15.dll” \no_namespace
  rename ( “EOF”, “adoEOF” )
  重命名EOF是必要的,因为典型的VC应用都已经定义了EOF作为常数-1。
  通常来说,操作一个自动化对象需要定义和初始化一个用来操作的变量。可以通过使用智能指针
  (_com_ptr_t)的构造函数传递一个有效的CLSID或者是PROGID,也可以通过_com_ptr_t::CreateInstance()方法来定义对象。具体代码如下所示:
  _ConnectionPtr Conn1( __uuidof( Connection ) );
  也可以采用下面的代码实现同样的功能:
  _ConnectionPtr Conn1 = NULL; //定义对象
  HRESULT hr = S_OK;
  //创建实例
  hr =Conn1.CreateInstance( __uuidof( Connection ) );
  推荐采用第二种方式,因为用第一种方式不能返回一个失败的HRESULT,所以也就不能判断ADO连接对象是成功还是失败,以及失败的原因。注意这里的__uuidof( Connection)中的Connection是在.tlh文件中定义的。通过把它传递给方法CreateInstance,就可以创建一个有效的 ADOConnection对象。
  需要注意的是#import的no_namespace属性,它告诉编译器该类在不在一个单独的名字空间中。使用no_namespace意味着不需要在初始化变量时引用名字空间。当然如果在应用中需要导入多个类型库时,最好不要使用 no_namespace,以免引起名字冲突。
  下面是一个简单的采用了#import方法的基于ADO应用的示例代码:
  #include
  #import rename(“EOF”, “adoEOF”)
  void main()
  {
  HRESULT hr = S_OK;
  //因为没有在#import中指定no_namespace,所以必须采用ADODB::这样的形式来定义变量类型
  ADODB::_RecordsetPtr Rs1 = NULL;
  //通过ODBC建立ADO连接
  _bstr_t Connect( “DSN=AdoDemo;UID=sa;PWD=;” );
  _bstr_t Source ( “SELECT * FROM Authors” );
  CoInitialize();
  //初始化Rs1对象
  hr = Rs1.CreateInstance( __uuidof( ADODB::Recordset ) );
  //省略对返回值hr的判断
  Rs1->Open( Source,
  Aonnect,
  ADODB::adOpenForwardOnly,
  ADODB::adLockReadOnly,
  -1 );
  //此处可以添加对记录集Rs1进行操作的代码
  Rs1->Close();
  Rs1 = NULL;
  ::MessageBox( NULL,“Success!”,“”,MB_OK );
  CoUninitialize();
  }

用MFC OLE创建ADO应用

  MFC OLE同样能够封装(wrapper)一个类型库,但是与#import不同,它不能从类型库中产生枚举类型。MFC类CString和 COleVariant隐藏了BSTRS和Variants的细节。由MFC OLE产生的类都继承了类ColeDispatchDriver,由ADO产生的失败的HRESULTS被封装在类 ColeDispatchException中。
  用MFC OLE ClassWizard创建ADO应用的步骤如下:
  从Tools菜单中,选择Options选项中的Directories tab条目,在Show Directories中的Library Files中增加路径C:\program files\common files\system\ado,设置包含ADO类型库的路径。
  从View菜单中,激活ClassWizard,点击Add Class按钮并选择“From A Type Library...”选项,然后在Type Library dialog box对话框中,从C:\program files\common files\system\ado中选择文件msado15.dll,在Confirm Classes对话框中,选择所有列出的类并按OK按钮退出ClassWizard。这样,ClassWizard便生成了两个文件msado15.h和 msado15.cpp。
  下面是实现ADO应用的示例代码:
  //初始化COM对象
  AfxOleInit();
  ...
  //定义数据集对象
  _Recordset Rs1;
  COleException e;
  COleVariant Connect( “DSN=AdoDemo;UID=sa;PWD=;” );
  COleVariant Source ( “SELECT * FROM Authors” );
  //创建数据集对象
  Rs1.CreateDispatch(“ADODB.Recordset.2.0”,&e );
  Rs1.Open( (VARIANT) Source,
  (VARIANT) Connect,
  0, 1, -1 );
  //此处可以添加对结果集Rs1进行处理的代码
  Rs1.Close();
  Rs1.ReleaseDispatch();
  AfxMessageBox(“Success!”);

用COM API创建ADO工程

  #import和MFC OLE都围绕着一个给定的自动化对象产生了一个封装类,它们分别继承自_com_ptr_t和ColeDispatchDriver。其实也可以通过使用 Windows API函数直接初始化ADO对象。为了直接使用ADO和COM对象,需要添加两个头文件adoid.h和adoint.h,这两个头文件定义了 CLSIDs、接口定义和操作ADO类型库所需要的枚举类型。此外,还需要增加头文件INITGUID.H。
  为了能够编译用COM API创建的ADO工程文件,还需要在机器中安装OLE DB SDK或者是MSDASDK工具。下面是利用API创建ADO的简单的示例代码:
  #include
  #include
  #include “adoid.h” // ADO的GUID's
  #include “adoint.h” // ADO的类、枚举等等
  void main()
  {
  HRESULT hr = S_OK;
  // ADORecordset 是在adoint.h中定义的
  ADORecordset*Rs1 = NULL;
  VARIANT Source;
  VARIANT Connect;
  VariantInit( &Source );
  VariantInit( &Connect );
  Source.vt = VT_BSTR;
  Source.bstrVal = ::SysAllocString( L“SELECT * FROM Authors”);
  Connect.vt = VT_BSTR;
  Connect.bstrVal = ::SysAllocString( L“DSN=AdoDemo;UID=sa;PWD=;” );
  hr = CoCreateInstance( CLSID_CADORecordset,
  NULL,
  CLSCTX_INPROC_SERVER,
  IID_IADORecordset,
  (LPVOID *) &Rs1 );
  if( SUCCEEDED( hr ) ) hr = Rs1->Open
  (Source,
  Connect,
  adOpenForwardOnly,
  adLockReadOnly,
  -1 );
  //对记录集Rs1进行处理
  if( SUCCEEDED( hr ) ) hr = Rs1->Close();
  if( SUCCEEDED( hr ) ) { Rs1->Release(); Rs1 = NULL; }
  if( SUCCEEDED( hr ) ) ::MessageBox( NULL, “Success!”, “”, MB_OK );
  }
  C++ Extensions
  如果用C++进行ADO应用程序开发,应该使用ADO C++ Extensions。我们知道,用VB或者VBScript来操作ADO是非常方便的,但是如果使用C++或者是Java,就必须要处理类似 Variants这样的数据结构以实现和C++数据结构的转换,而这种处理无疑是所有C++开发人员都很头疼的事情。但如果使用C++ Extensions的话,ADO就不需要从数据提供者处得到列信息,而是在设计时刻使用开发人员提供的列信息。以下是一个简单的示例:
  //创建和具体记录相对应的类
  class CAuthor : public CADORecordBinding
  {
  BEGIN_ADO_BINDING(CCustomRs1)
  ADO_VARIABLE_LENGTH_ENTRY4(1,
  adVarChar, m_szau_id, sizeof(m_szau_id), FALSE)
  ADO_VARIABLE_LENGTH_ENTRY4(2,
  adVarChar,m_szau_fname,sizeof(m_szau_fname), FALSE)
  ADO_VARIABLE_LENGTH_ENTRY4(3,
  adVarChar,m_szau_lname,sizeof(m_szau_lname), FALSE)
  END_ADO_BINDING()
  protected:
  char m_szau_id[12];
  char m_szau_fname[21];
  char m_szau_lname[41];
  };
  void FetchAuthorData()
  {
  CAuthor author;
  //记录集对象
  _RecordsetPtr pRs;
  IADORecordBinding *piAdoRecordBinding;
  //获取COM对象接口指针
  pRs.CreateInstance(__uuidof(Recordset));
  //得到需要的记录集
  pRs->Open(“select au_id,au_fname,au_lname from Employees”,“Provider=SQLOLEDB;Data Source=sureshk1;Database=pubs;User Id=sa;Password=;”,
  adOpenForwardOnly,
  adLockReadOnly,
  adCmdText);
  //查询接口IADORecordBinding
  pRs->QueryInterface(__uuidof(IADORecordBinding),(LPVOID*)&piAdoRecordBinding);
  //绑定对象
  piAdoRecordBinding->BindToRecordset(&author);
  //得到记录中的相关内容
  while (VARIANT_FALSE == pRs->EOF) {
  printf(“%s %s %s”, author.m_szau_id,
  author.m_szau_fname, author.m_szau_lname);
  pRs->MoveNext();
  }
  //释放对象

利用ADO ACCESS数据库

  ACCESS是一个关系型桌面数据库管理系统,它可以用来建立中小型号的数据库应用系统,使用非常广泛.下面介绍如何使用ADO连接ACCESS数据库.在连接数据库时,需要使用Connection对象的Open方法打开与数据源的连接.
  语法:Connectoin.open Connectionstring,userID,password,openoptions
  Open方法的参数表说明如下
  Open方法参数说明
  ConnectionString (可选)字符串,包含连接信息,参照(ConnectionSting)属性可获得有效调协的详细信息
  UserID (可选)字符串,包含建立连接时所使用的用户名称
  Password (可选)字符串,包含建立连接时所用的密码
  openoptions (可选)ConnectionEnum值.如果调协为adConnectoAsync,则异步打开连接,当连接可用时将产生ConnectComplete事件
  ADO(ActiveX Data Objects)是一种操作 Microsoft 所支持的数据库的新技术。在 ASP 中,ADO可以看作是一个服务器组件(Server Component),更简单点说,是一系列的对象,应用这些功能强大的对象,即可轻松完成对数据库复杂的操作。本文中个性化页面的实现便大量地用到了 ADO 技术。具体的操作步骤可以归纳为以下几步:
  (1) 创建数据库源名(DSN)
  (2) 创建数据库链接(Connection)
  (3) 创建数据对象
  (4) 操作数据库
  (5) 关闭数据对象和链接
阅读全文 | 回复(0) | 引用通告 | 编辑 | By: 皮皮爸爸

发表评论:

    大名:
    密码: (游客无须输入密码)
    主页:
    标题:
    80
Powered by Oblog.