Chinaunix首页 | 论坛 | 博客
  • 博客访问: 425813
  • 博文数量: 79
  • 博客积分: 2886
  • 博客等级: 少校
  • 技术积分: 968
  • 用 户 组: 普通用户
  • 注册时间: 2008-05-16 10:33
文章分类

全部博文(79)

文章存档

2013年(7)

2012年(17)

2011年(28)

2010年(25)

2009年(1)

2008年(1)

我的朋友

分类: C/C++

2011-01-20 16:18:58

ADO是Microsoft为最新和最强大的数据访问范例OLE DB 而设计的,是一个便于使用的应用程序接口。
ADO 使您能够编写应用程序以通过 OLE.DB 提供者访问和操作数据库服务器中的数据。
ADO 最主要的优点是易于使用、速度快、内存支出少和磁盘遗迹小。
ADO 在关键的应用方案中使用最少的网络流量,并且在前端和数据源之间使用最少的层数,所有这些都是为了提供轻量、高性能的接口。
OLE DB是一组”组件对象模型”(COM) 接口,是新的数据库低层接口,它封装了ODBC的功能,并以统一的方式访问存储在不同信息源中的数据。
OLE DB是Microsoft UDA(Universal Data Access)策略的技术基础。
OLE DB 为任何数据源提供了高性能的访问,这些数据源包括关系和非关系数据库、电子邮件和文件系统、文本和图形、自定义业务对象等等。
也就是说,OLE DB 并不局限于 ISAM、Jet 甚至关系数据源,它能够处理任何类型的数据,而不考虑它们的格式和存储方法。
在实际应用中,这种多样性意味着可以访问驻留在 Excel 电子数据表、文本文件、电子邮件/目录服务甚至邮件服务器,诸如 Microsoft Exchange 中的数据.

但是,OLE DB 应用程序编程接口的目的是为各种应用程序提供最佳的功能,它并不符合简单化的要求。
您需要的API 应该是一座连接应用程序和 OLE DB 的桥梁,这就是 ActiveX Data Objects (ADO)。

使用步骤:
(1)使用ADO前必须在工程的stdafx.h文件里用直接引入符号#import引入ADO库文件,以使编译器能正确编译。代码如下所示:
代码1:用#import引入ADO库文件
#import "c:\program files\common files\system\ado\msado15.dll" 
no_namespaces rename("EOF" adoEOF")
这行语句声明在工程中使用ADO,但不使用ADO的名字空间,并且为了避免常数冲突,将常数EOF改名为adoEOF。
现在不需添加另外的头文件,就可以使用ADO接口了。

(2) 初始化OLE/COM库环境
必须注意的是,ADO库是一组COM动态库,这意味应用程序在调用ADO前,必须初始化OLE/COM库环境。
在MFC应用程序里,一个比较好的方法是在应用程序主类的InitInstance成员函数里初始化OLE/COM库环境。
代码2:初始化OLE/COM库环境

BOOL CADOApp::InitInstance()
{
if(!AfxOleInit())
{
AfxMessageBox(“OLE初始化出错!”);
return FALSE;
……
}
(3)#import 包含后就可以使用ADO库的三个接口了
ADO库包含三个基本接口:_ConnectionPtr接口、_CommandPtr接口和_RecordsetPtr接口。

<1> _ConnectionPtr接口返回一个记录集或一个空指针。
它的工作原理是首先创建一个_ConnectionPtr接口实例,接着指向并打开一个ODBC数据源或OLE DB数据提供者(Provider)。
通常使用它来创建一个数据连接或执行一条不返回任何结果的SQL语句,如一个存储过程。
使用_ConnectionPtr接口返回一个记录集不是一个好的使用方法。
通常同CDatabase一样,使用它创建一个数据连接,然后使用其它对象执行数据输入输出操作。
<2> _CommandPtr接口返回一个记录集。它提供了一种简单的方法来执行返回记录集的存储过程和SQL语句。
在使用_CommandPtr接口时,你可以利用全局_ConnectionPtr接口,也可以在_CommandPtr接口里直接使用连接串。
如果你只执行一次或几次数据访问操作,后者是比较好的选择。但如果你要频繁访问数据库,并要返回很多记录集,
那么,你应该使用全局_ConnectionPtr接口创建一个数据连接,然后使用_CommandPtr接口执行存储过程和SQL语句。
<3>_RecordsetPtr是一个记录集对象。
与以上两种对象相比,它对记录集提供了更多的控制功能,如记录锁定,游标控制等。
同_CommandPtr接口一样,它不一定要使用一个已经创建的数据连接,可以用一个连接串代替连接指针赋给_RecordsetPtr的connection成员变量,
让它自己创建数据连接。如果你要使用多个记录集,最好的方法是同Command对象一样使用已经创建了数据连接的全局_ConnectionPtr接口,
然后使用_RecordsetPtr执行存储过程和SQL语句。
(4)三个接口的使用
<1> 连接和关闭数据库

//连接

AfxOleInit();//初始化
HRESULT hr;
try
{
     hr = m_pConnection.CreateInstance("ADODB.Connection");///创建Connection对象
     if(SUCCEEDED(hr))
     {
         m_pConnection->ConnectionTimeout = 0;
         hr = m_pConnection->Open( "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=db.mdb", "", "", adModeUnknown);
         //m_pConnection->PutDefaultDatabase ((_bstr_t)"DB");//设置默认数据库
         m_pCommand.CreateInstance(__uuidof(Command));
         m_pCommand->CommandTimeout = 5;
         m_pCommand->ActiveConnection = m_pConnection;
     }
}catch(_com_error e)///捕捉异常
{
     CString errormessage;
     errormessage.Format("连接数据库失败! 错误信息:%s",e.ErrorMessage());
     AfxMessageBox(errormessage);///显示错误信息
//关闭
//如果数据库连接有效
if( m_pConnection->State )
     m_pConnection->Close();
m_pConnection = NULL;  
//设置连接时间
     pConnection->put_ConnectionTimeout(long(5));


tips:
1.Open方法的原型是这样的:

HRESULT Recordset15::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 = -1,///不作特别指定

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

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

adOpenDynamic = 2,///动态光标。所有数据库的操作都会立即在各用户记录集上反应出来。 adOpenStatic = 3///静态光标。它为你的记录集产生一个静态备份,但其它用户的新增、删除、更新操 作对你的记录集来说是不可见的。 };

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

enum LockTypeEnum { adLockUnspecified = -1,///未指定

adLockReadOnly = 1,///只读记录集

adLockPessimistic = 2,悲观锁定方式。数据在更新时锁定其它所有动作,这是最安全的锁定机制 adLockOptimistic = 3,乐观锁定方式。只有在你调用Update方法时才锁定记录。在此之前仍然可以做数 据的更新、插入、删除等动作

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

5.option可以取以下值

adCmdText:表明CommandText是文本命令

adCmdTable:表明CommandText是一个表名

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

<2> 打开一个结果集
//打开,首先创建一个_RecordsetPtr实例,然后调用Open()得到一条SQL语句的执行结果
_RecordsetPtr m_pRecordset;
m_pRecordset.CreateInstance(__uuidof(Recordset));
// 在ADO操作中建议语句中要常用try...catch()来捕获错误信息,
// 因为它有时会经常出现一些意想不到的错误。jingzhou xu
try
{
     m_pRecordset->Open("SELECT * FROM DemoTable",// 查询DemoTable表中所有字段
       m_pConnection.GetInterfacePtr(),  // 获取库接库的IDispatch指针
         adOpenDynamic,
         adLockOptimistic,
         adCmdText);
}catch(_com_error *e)
{
     AfxMessageBox(e->ErrorMessage());
//关闭结果集
m_pRecordset->Close(); 

<3> 操作一个结果集
//遍历(读取)
     //a)、用pRecordset->adoEOF来判断数据库指针是否已经移到结果集的末尾了;
//m_pRecordset->BOF判断是否 在第一条记录前面:
while(!m_pRecordset->adoEOF)
{
     var = m_pRecordset->GetCollect("Name");
     if(var.vt != VT_NULL)
     strName = (LPCSTR)_bstr_t(var);
     var = m_pRecordset->GetCollect("Age");
     if(var.vt != VT_NULL)
     strAge = (LPCSTR)_bstr_t(var);
     m_AccessList.AddString( strName + " --> "+strAge );
     m_pRecordset->MoveNext();
     //b)、取得一个字段的值的办法有两种办法
     //一是 表示取得第0个字段的值
rdset->GetCollect("Name");
// 或者
rdset->GetCollect(_variant_t(long(0));

     //二是
pRecordset->get_Collect("COLUMN_NAME");
        //或者 
pRecordset->get_Collect(long(index)); 
---------------------------------------------------------------------------
//添加
     //调用m_pRecordset->AddNew();
m_pRecordset->AddNew();
     //调用m_pRecordset->PutCollect();给每个字段赋值
m_pRecordset->PutCollect("ID",_variant_t((long)(i+10)));
     //调用m_pRecordset->Update();确认
m_pRecordset->Update();
---------------------------------------------------------------------------
(4)、删除
//把记录指针移动到要删除的记录上,然后调用
Delete(adAffectCurrent)
try
{
     // 假设删除第二条记录
     m_pRecordset->MoveFirst();
     m_pRecordset->Move(1);       
     // 从0开始
     m_pRecordset->Delete(adAffectCurrent); 
     // 参数adAffectCurrent为删除当前记录
     m_pRecordset->Update();
}catch(_com_error *e)
{
     AfxMessageBox(e->ErrorMessage());
(5)关于数据类型转换
由于COM对象是跨平台的,它使用了一种通用的方法来处理各种类型的数据,因此CString 类和COM对象是不兼容的,
我们需要一组API来转换COM对象和C++类型的数据。_vatiant_t和_bstr_t就是这样两种对象。
它们提供了通用的方法转换COM对象和C++类型的数据。

阅读(783) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~