其他语言

位置:IT落伍者 >> 其他语言 >> 浏览文章

Visual C++开发数据库基础之ADO篇


发布日期:2022年08月31日
 
Visual C++开发数据库基础之ADO篇

ADO简介

ADO(ActiveX Data Object)是Microsoft数据库应用程序开发的新接口是建立在OLE DB之上的高层数据库访问技术请不必为此担心即使你对OLE DBCOM不了解也能轻松对付ADO因为它非常简单易用甚至比你以往所接触的ODBC APIDAORDO都要容易使用并不失灵活性本文将详细地介绍在VC下如何使用ADO来进行数据库应用程序开发并给出示例代码

基本流程

万事开头难任何一种新技术对于初学者来说最重要的还是入门掌握其要点让我们来看看ADO数据库开发的基本流程吧!

()初始化COM库引入ADO库定义文件

()用Connection对象连接数据库

()利用建立好的连接通过ConnectionCommand对象执行SQL命令或利用Recordset对象取得结果记录集进行查询处理

()使用完毕后关闭连接释放对象

准备工作:

为了大家都能测试本文提供的例子我们采用Access数据库您也可以直接在我们提供的示例代码中找到这个testmdb

下面我们将详细介绍上述步骤并给出相关代码

】COM库的初始化

我们可以使用AfxOleInit()来初始化COM库这项工作通常在CWinApp::InitInstance()的重载函数中完成请看如下代码:

BOOL CADOTestApp::InitInstance()

{

AfxOleInit();

】用#import指令引入ADO类型库

我们在stdafxh中加入如下语句(stdafxh这个文件哪里可以找到?你可以在FileView中的Header Files里找到)

#import c:\program files\common files\system\ado\msadodll no_namespace rename(EOFadoEOF)

这一语句有何作用呢?其最终作用同我们熟悉的#include类似编译的时候系统会为我们生成msadotlhadotli两个C++头文件来定义ADO库

几点说明:

() 您的环境中msadodll不一定在这个目录下请按实际情况修改

() 在编译的时候肯能会出现如下警告对此微软在MSDN中作了说明并建议我们不要理会这个警告

msadotlh() : warning C: unary minus operator applied to unsigned type result still unsigned

】创建Connection对象并连接数据库

首先我们需要添加一个指向Connection对象的指针:

_ConnectionPtr m_pConnection;

下面的代码演示了如何创建Connection对象实例及如何连接数据库并进行异常捕捉

BOOL CADOTestDlg::OnInitDialog()

{

CDialog::OnInitDialog();

HRESULT hr;

try

{

hr = m_pConnectionCreateInstance(ADODBConnection);///创建Connection对象

if(SUCCEEDED(hr))

{

hr = m_pConnection>Open(Provider=MicrosoftJetOLEDB;Data Source=testmdbadModeUnknown);///连接数据库

///上面一句中连接字串中的Provider是针对ACCESS环境的对于ACCESS需要改为:Provider=MicrosoftJetOLEDB; }

}

catch(_com_error e)///捕捉异常

{

CString errormessage;

errormessageFormat(连接数据库失败!\r\n错误信息:%seErrorMessage());

AfxMessageBox(errormessage);///显示错误信息

}

在这段代码中我们是通过Connection对象的Open方法来进行连接数据库的下面是该方法的原型

HRESULT Connection::Open ( _bstr_t ConnectionString _bstr_t UserID _bstr_t Password long Options )

ConnectionString为连接字串UserID是用户名 Password是登陆密码Options是连接选项用于指定Connection对象对数据的更新许可权

Options可以是如下几个常量:

adModeUnknown:缺省当前的许可权未设置

adModeRead:只读

adModeWrite:只写

adModeReadWrite:可以读写

adModeShareDenyRead:阻止其它Connection对象以读权限打开连接

adModeShareDenyWrite:阻止其它Connection对象以写权限打开连接

adModeShareExclusive:阻止其它Connection对象打开连接

adModeShareDenyNone:允许其它程序或对象以任何权限建立连接

我们给出一些常用的连接方式供大家参考:

()通过JET数据库引擎对ACCESS数据库的连接


m_pConnection>Open(Provider=MicrosoftJetOLEDB;Data Source=C:\\testmdbadModeUnknown);

()通过DSN数据源对任何支持ODBC的数据库进行连接:

m_pConnection>Open(Data Source=adotest;UID=sa;PWD=;adModeUnknown);

()不通过DSN对SQL SERVER数据库进行连接

m_pConnection>Open(driver={SQL Server};Server=;DATABASE=vckbase;UID=sa;PWD=adModeUnknown);

其中Server是SQL服务器的名称DATABASE是库的名称

Connection对象除Open方法外还有许多方法我们先介绍Connection对象中两个有用的属性ConnectionTimeOut与State

ConnectionTimeOut用来设置连接的超时时间需要在Open之前调用例如:

m_pConnection>ConnectionTimeout = ;///设置超时时间为

m_pConnection>Open(Data Source=adotest;adModeUnknown);

State属性指明当前Connection对象的状态表示关闭表示已经打开我们可以通过读取这个属性来作相应的处理例如:

if(m_pConnection>State)

m_pConnection>Close(); ///如果已经打开了连接则关闭它

】执行SQL命令并取得结果记录集

为了取得结果记录集我们定义一个指向Recordset对象的指针:_RecordsetPtr m_pRecordset;

并为其创建Recordset对象的实例: m_pRecordsetCreateInstance(ADODBRecordset);

SQL命令的执行可以采用多种形式下面我们一进行阐述

()利用Connection对象的Execute方法执行SQL命令

Execute方法的原型如下所示:

_RecordsetPtr Connection::Execute ( _bstr_t CommandText VARIANT * RecordsAffected long Options ) 其中CommandText是命令字串通常是SQL命令参数RecordsAffected是操作完成后所影响的行数 参数Options表示CommandText中内容的类型Options可以取如下值之一

adCmdText:表明CommandText是文本命令

adCmdTable:表明CommandText是一个表名

adCmdProc:表明CommandText是一个存储过程

adCmdUnknown:未知

Execute执行完后返回一个指向记录集的指针下面我们给出具体代码并作说明

_variant_t RecordsAffected;

///执行SQL命令CREATE TABLE创建表格usersusers包含四个字段:整形ID字符串username整形old日期型birthday

m_pConnection>Execute(CREATE TABLE users(ID INTEGERusername TEXTold INTEGERbirthday DATETIME)&RecordsAffectedadCmdText);

///往表格里面添加记录

m_pConnection>Execute(INSERT INTO users(IDusernameoldbirthday) valueS ( Washington//)&RecordsAffectedadCmdText);

///将所有记录old字段的值加一

m_pConnection>Execute(UPDATE users SET old = old+&RecordsAffectedadCmdText);

///执行SQL统计命令得到包含记录条数的记录集

m_pRecordset = m_pConnection>Execute(SELECT COUNT(*) FROM users&RecordsAffectedadCmdText);

_variant_t vIndex = (long);

_variant_t vCount = m_pRecordset>GetCollect(vIndex);///取得第一个字段的值放入vCount变量

m_pRecordset>Close();///关闭记录集

CString message;

messageFormat(共有%d条记录vCountlVal);

AfxMessageBox(message);///显示当前记录条数

()利用Command对象来执行SQL命令

_CommandPtr m_pCommand;

m_pCommandCreateInstance(ADODBCommand);

_variant_t vNULL;

vNULLvt = VT_ERROR;

vNULLscode = DISP_E_PARAMNOTFOUND;///定义为无参数

m_pCommand>ActiveConnection = m_pConnection;///非常关键的一句将建立的连接赋值给它

m_pCommand>CommandText = SELECT * FROM users;///命令字串

m_pRecordset = m_pCommand>Execute(&vNULL&vNULLadCmdText);///执行命令取得记录集

在这段代码中我们只是用Command对象来执行了SELECT查询语句Command对象在进行存储过程的调用中能真正体现它的作用下次我们将详细介绍

()直接用Recordset对象进行查询取得记录集

例如

m_pRecordset>Open(SELECT * FROM users_variant_t((IDispatch *)m_pConnectiontrue)adOpenStaticadLockOptimisticadCmdText);

Open方法的原型是这样的:

HRESULT Recordset::Open ( const _variant_t & Source const _variant_t & ActiveConnection enum CursorTypeEnum CursorType enum LockTypeEnum LockType long Options )

其中

①Source是数据查询字符串

②ActiveConnection是已经建立好的连接(我们需要用Connection对象指针来构造一个_variant_t对象)

③CursorType光标类型它可以是以下值之一请看这个枚举结构:


enum CursorTypeEnum

{

adOpenUnspecified = ///不作特别指定

adOpenForwardOnly = ///前滚静态光标这种光标只能向前浏览记录集比如用MoveNext向前滚动这种方式可以提高浏览速度但诸如BookMarkRecordCountAbsolutePositionAbsolutePage都不能使用

adOpenKeyset = ///采用这种光标的记录集看不到其它用户的新增删除操作但对于更新原有记录的操作对你是可见的

adOpenDynamic = ///动态光标所有数据库的操作都会立即在各用户记录集上反应出来

adOpenStatic = ///静态光标它为你的记录集产生一个静态备份但其它用户的新增删除更新操作对你的记录集来说是不可见的

};

④LockType锁定类型它可以是以下值之一请看如下枚举结构

enum LockTypeEnum

{

adLockUnspecified = ///未指定

adLockReadOnly = ///只读记录集

adLockPessimistic = 悲观锁定方式数据在更新时锁定其它所有动作这是最安全的锁定机制

adLockOptimistic = 乐观锁定方式只有在你调用Update方法时才锁定记录在此之前仍然可以做数据的更新插入删除等动作

adLockBatchOptimistic = 乐观分批更新编辑时记录不会锁定更改插入及删除是在批处理模式下完成

};

⑤Options请参考本文中对Connection对象的Execute方法的介绍

】记录集的遍历更新

根据我们刚才通过执行SQL命令建立好的users表它包含四个字段:IDusernameoldbirthday

以下的代码实现打开记录集遍历所有记录删除第一条记录添加三条记录移动光标到第二条记录更改其年龄保存到数据库

_variant_t vUsernamevBirthdayvIDvOld;

_RecordsetPtr m_pRecordset;

m_pRecordsetCreateInstance(ADODBRecordset);

m_pRecordset>Open(SELECT * FROM users_variant_t((IDispatch*)m_pConnectiontrue)adOpenStaticadLockOptimisticadCmdText);

while(!m_pRecordset>adoEOF)///这里为什么是adoEOF而不是EOF呢?还记得rename(EOFadoEOF)这一句吗?

{

vID = m_pRecordset>GetCollect(_variant_t((long)));///取得第列的值开始计数你也可以直接给出列的名称如下一行

vUsername = m_pRecordset>GetCollect(username);///取得username字段的值

vOld = m_pRecordset>GetCollect(old);

vBirthday = m_pRecordset>GetCollect(birthday);

///在DEBUG方式下的OUTPUT窗口输出记录集中的记录

if(vIDvt != VT_NULL && vUsernamevt != VT_NULL && vOldvt != VT_NULL && vBirthdayvt != VT_NULL)

TRACE(id:%d姓名:%s年龄:%d生日:%s\r\nvIDlVal(LPCTSTR)(_bstr_t)vUsernamevOldlVal(LPCTSTR)(_bstr_t)vBirthday);

m_pRecordset>MoveNext();///移到下一条记录

}

m_pRecordset>MoveFirst();///移到首条记录

m_pRecordset>Delete(adAffectCurrent);///删除当前记录

///添加三条新记录并赋值

for(int i=;i<;i++)

{

m_pRecordset>AddNew();///添加新记录

m_pRecordset>PutCollect(ID_variant_t((long)(i+)));

m_pRecordset>PutCollect(username_variant_t(叶利钦));

m_pRecordset>PutCollect(old_variant_t((long)));

m_pRecordset>PutCollect(birthday_variant_t());

}

m_pRecordset>Move(_variant_t((long)adBookmarkFirst));///从第一条记录往下移动一条记录即移动到第二条记录处

m_pRecordset>PutCollect(_variant_t(old)_variant_t((long)));///修改其年龄

m_pRecordset>Update();///保存到库中

】关闭记录集与连接

记录集或连接都可以用Close方法来关闭

m_pRecordset>Close();///关闭记录集

m_pConnection>Close();///关闭连接

至此我想您已经熟悉了ADO操作数据库的大致流程也许您已经胸有成竹也许您还有点胡涂不要紧!建议你尝试写几个例子这样会更好地熟悉ADO最后我给大家写了一个小例子例子中读出所有记录放到列表控件中并可以添加删除修改记录

后记限于篇幅ADO中的许多内容还没有介绍下次我们将详细介绍Recordset对象的属性方法并解决几个关键的技术绑定方式处理记录集数据存储过程的调用事务处理图象在数据库中的保存与读取与表格控件的配合使用等

上一篇:Windows via C/C++ —进程(一)

下一篇:C++/CLI中有效使用非托管并列缓存