ado数据库编程入门
李安东编写
2002年2月28日
摘要 本文简要介绍了在vc++ 6.0中使用 ado进行客户端数据库编程的基本步骤,以及常见问题的解决方法,可供入门级的参考之用。
关键字 ado vc++ 数据库编程
ado 是目前在windows环境中比较流行的客户端数据库编程技术。ado是建立在ole db底层技术之上的高级编程接口,因而它兼具有强大的数据处理功能(处理各种不同类型的数据源、分布式的数据处理等等)和极其简单、易用的编程接口,因而得到了广泛的应用。而且按微软公司的意图,ole db和ado将逐步取代 odbc和dao。现在介绍ado各种应用的文章和书籍有很多,本文着重站在初学者的角度,简要探讨一下在vc++中使用ado编程时的一些问题。我们希望阅读本文之前,您对ado技术的基本原理有一些了解。
一、在vc++中使用ado编程
ado实际上就是由一组automation对象构成的组件,因此可以象使用其它任何automation对象一样使用ado。ado中最重要的对象有三个:connection、command和recordset,它们分别表示连接对象、命令对象和记录集对象。如果您熟悉使用mfc中的odbc类(cdatabase、crecordset)编程,那么学习ado编程就十分容易了。
使用ado编程时可以采用以下三种方法之一:
1、使用预处理指令#import
#import "c:\program files\common files\system\ado\msado15.dll" \
no_namespace rename("eof", "endoffile")
但要注意不能放在stdafx.h文件的开头,而应该放在所有include指令的后面。否则在编译时会出错。
程序在编译过程中,vc++会读出msado15.dll中的类型库信息,自动产生两个该类型库的头文件和实现文件msado15.tlh和msado15.tli(在您的debug或release目录下)。在这两个文件里定义了ado的所有对象和方法,以及一些枚举型的常量等。我们的程序只要直接调用这些方法就行了,与使用mfc中的coledispatchdriver类调用automation对象十分类似。
2、使用mfc中的cidispatchdriver
就是通过读取msado15.dll中的类型库信息,建立一个coledispatchdriver类的派生类,然后通过它调用ado对象。
3、直接用com提供的api
如使用如下代码:
clsid clsid;
hresult hr = ::clsidfromprogid(l"adodb.connection", &clsid);
if(failed(hr))
{...}
::cocreateinstance(clsid, null, clsctx_server, iid_idispatch, (void **)
&pdispatch);
if(failed(hr))
{...}
以上三种方法,第一和第二种类似,可能第一种好用一些,第三种编程可能最麻烦。但可能第三种方法也是效率最高的,程序的尺寸也最小,并且对ado的控制能力也最强。
据微软资料介绍,第一种方法不支持方法调用中的默认参数,当然第二种方法也是这样,但第三种就不是这样了。采用第三种方法的水平也最高。当你需要绕过ado而直接调用ole db底层的方法时,就一定要使用第三种方法了。
ado编程的关键,就是熟练地运用ado提供的各种对象(object)、方法(method)、属性(property)和容器(collection)。另外,如果是在ms sql或oracle等大型数据库上编程,还要能熟练使用sql语言。
二、使用#import方法的编程步骤
这里建议您使用#import的方法,因为它易学、易用,代码也比较简洁。
1、 添加#import指令
打开stdafx.h文件,将下列内容添加到所有的include指令之后:
#include <icrsint.h> //include support for vc++ extensions
#import "c:\program files\common files\system\ado\msado15.dll" \
no_namespace rename("eof", "adoeof")
其中icrsint.h文件包含了vc++扩展的一些预处理指令、宏等的定义,用于com编程时使用。
2、定义_connectionptr型变量,并建立数据库连接
建立了与数据库服务器的连接后,才能进行其他有关数据库的访问和操作。ado使用connection对象来建立与数据库服务器的连接,所以它相当于mfc中的cdatabase类。和cdatabase类一样,调用connection对象的open方法即可建立与服务器的连接。
数据类型 _connectionptr实际上就是由类模板_com_ptr_t而得到的一个具体的实例类,其定义可以到msado15.tlh、comdef.h 和comip.h这三个文件中找到。在msado15.tlh中有:
_com_smartptr_typedef(_collection, __uuidof(_collection));
经宏扩展后就得到了_connectionptr类。_connectionptr类封装了connection对象的idispatch接口指针,及一些必要的操作。我们就是通过这个指针来操纵connection对象。类似地,后面用到的_commandptr和_recordsetptr类型也是这样得到的,它们分别表示命令对象指针和记录集对象的指针。
(1)、连接到ms sql server
注意连接字符串的格式,提供正确的连接字符串是成功连接到数据库服务器的第一步,有关连接字符串的详细信息参见微软msdn library光盘。
本例连接字符串中的server_name,database_name,user_name和password在编程时都应该替换成实际的内容。
_connectionptr pmyconnect=null;
hresult hr=pmyconnect.createinstance(__uuidof(connection)));
if(failed(hr))return;
_bstr_t strconnect="provider=sqloledb; server=server_name;"
"database=database_name; uid=user_name; pwd=password;"
//connecting to the database server now:
try{pmyconnect->open(strconnect,"","",null);}
catch (_com_error &e)
{
::messagebox(null,e.description(),"警告",mb_ok | mb_iconwarning);
}
注意connection对象的open方法中的连接字符串参数必须是bstr或_bstr_t类型。另外,本例是直接通过ole db provider建立连接,所以无需建立数据源。
(2)、通过odbc driver连接到database server
连接字符串格式与直接用odbc编程时的差不多:
_bstr_t strconnect="dsn=datasource_name; database=database_name; uid=user_name; pwd=password;"
此时与odbc编程一样,必须先建立数据源。
3、定义_recordsetptr型变量,并打开数据集
定义_recordsetptr型变量,然后通过它调用recordset对象的open方法,即可打开一个数据集。所以recordset对象与mfc中的crecordset类类似,它也有当前记录、当前记录指针的概念。如:
_recordsetptr m_precordset;
if(!failed(m_precordset.createinstance( __uuidof( recordset )))
{
m_pdoc->m_initialized=false;
return;
}
try{
m_precordset->open(_variant_t("mytable"),
_variant_t((idispatch *)pmyconnect,true), adopenkeyset,
adlockoptimistic, adcmdtable);
}
catch (_com_error &e)
{
::messagebox(null,"无法打开mytable表。","提示",
mb_ok | mb_iconwarning);
}
recordset对象的open方法非常重要,它的第一个参数可以是一个sql语句、一个表的名字或一个命令对象等等;第二个参数就是前面建立的连接对象的指针。此外,用connection和command对象的execute方法也能得到记录集,但是只读的。
4、读取当前记录的数据
我认为读取数据的最方便的方法如下:
try{
m_precordset->movefirst();
while(m_precordset->adoeof==variant_false)
{
//retrieve column&s value:
cstring sname=(char*)(_bstr_t)(m_precordset->fields->getitem