`
java2000.net
  • 浏览: 651335 次
  • 性别: Icon_minigender_1
  • 来自: 天津
社区版块
存档分类
最新评论
阅读更多

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 <windows.h>
#import <msado15.dll> 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();
}
2.用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!”);
3.用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 <windows.h>
#include <initguid.h>
#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();
}
//释放对象
piAdoRecordBinding->Release();
}
分享到:
评论

相关推荐

    ADO编程技术 vc++

    本篇文章将深入探讨ADO编程技术及其在VC++中的应用。 首先,我们需要了解ADO的核心组件。ADO包括以下几个主要对象: 1. **Connection**:这是与数据源建立连接的对象,通过设置连接字符串,我们可以连接到不同的...

    微软ADO编程指南

    由于内容是基于微软官方文档生成的,因此,这份ADO编程指南不仅包含了ADO编程的官方标准,还结合了实际操作中的示例代码,使得开发者在阅读文档后能够更加直观地理解ADO编程的实践应用。无论是初学者还是有经验的...

    DELPHI 下的ADO编程

    ### DELPHI下的ADO编程 #### 一、引言 Delphi是一款强大的集成开发环境(IDE),主要用于Windows应用程序的快速开发。它基于Object Pascal语言,提供了丰富的类库和组件,使得开发者能够高效地构建功能丰富的应用...

    轻松学用ADO编程(PDF格式).

    本书“轻松学用ADO编程”显然是一本旨在帮助初学者和开发者深入理解和掌握ADO技术的指南。ADO作为微软的数据访问技术,是OLE DB的一部分,提供了简单且高效的接口来操作数据库,包括查询、更新和删除数据。 1. ADO...

    轻松学用ADO编程

    本教程将深入浅出地讲解ADO编程的基本概念和实际应用。 1. ADO对象模型 ADO对象模型包括Connection、Recordset、Command、Parameter、Error等核心对象。Connection对象负责建立和数据库的连接,Recordset对象用于...

    ADO 编程 Access数据库

    **ADO编程Access数据库详解** 在IT领域,数据库编程是至关重要的技能之一,尤其是在Windows应用程序开发中。本教程将深入探讨如何使用ActiveX Data Objects (ADO) 技术与Microsoft Access数据库进行交互,这对于...

    MFC下的ADO编程入门实例

    这个"MFC下的ADO编程入门实例"是针对初学者设计的,旨在帮助开发者理解如何在MFC应用程序中利用ADO来连接数据库并执行基本操作。 **一、MFC与ADO** MFC是微软提供的C++类库,它为Windows应用程序开发提供了丰富的...

    ADO编程范例

    在这个“ADO编程范例”中,包含了九个示例,每个示例都展示了ADO的不同用法和功能,通过这些源代码,我们可以深入理解如何在实际项目中应用ADO。下面将分别对这些范例进行详细介绍: 1. 连接数据库:这个范例演示了...

    ADO数据库编程应用

    ### ADO数据库编程应用知识点详解 #### 一、概述 ADO (ActiveX Data Objects) 是一种用于连接数据库的标准接口,由Microsoft开发。它提供了一种简单而强大的方式来访问多种类型的数据库,包括关系型数据库(如MS ...

    ADO数据库编程入门(VC)

    ADO数据库编程入门 ...现在介绍ADO各种应用的文章和书籍有很多,本文着重站在初学者的角度,简要探讨一下在VC++中使用ADO编程时的一些问题。我们希望阅读本文之前,您对ADO技术的基本原理有一些了解。

    ADO数据库编程教程

    ### ADO数据库编程教程知识点详解 #### 一、ADO简介 **ActiveX Data Objects (ADO)** 是一种由Microsoft开发的数据访问技术,它提供了一个简单且高效的方法来访问各种类型的数据库。ADO作为OLE DB的一种高级封装层...

    ADO数据库编程实例

    - **ADODemo**:本书用于阐述ADO数据库编程的实例应用程序,主要实现了以下功能: - 会员注册登记与退会操作。 - 会员及其消费记录的查询。 - 社团的创建、查询及撤销管理。 - **运行效果**:该程序提供了一个...

    ADO编程手册

    《ADO编程手册》是一本详尽的指南,专注于ActiveX Data Objects(简称ADO)的使用和开发。ADO是Microsoft提供的一种用于访问和操作数据库的核心组件,它为开发者提供了与各种数据库系统交互的能力,包括关系型数据库...

    商业编程-源码-ADO编程实例.zip

    "商业编程-源码-ADO编程实例.zip" 这个标题表明,这个压缩包包含的是与商业编程相关的源代码,特别关注的是ADO(ActiveX Data Objects)编程的实际应用实例。ADO是微软开发的一种数据访问技术,它允许程序员通过统一...

    windows ADO数据库编程技术

    在ADO编程中,SQL用于构造查询语句,获取、更新或删除数据库中的数据。通过Command对象的CommandText属性,我们可以设置SQL命令,并通过Execute方法执行。 综上所述,"windows ADO数据库编程技术"涵盖了从基础的ADO...

    Visual C++ ADO 数据库编程入门

    在ADO编程中,最重要的三个对象是`Connection`、`Command`和`Recordset`: - **Connection**:负责与数据库服务器建立连接。 - **Command**:用于执行SQL语句或其他数据库命令。 - **Recordset**:存储查询结果或...

Global site tag (gtag.js) - Google Analytics