读写数据库的技术很多,现在多用ADO。ADO以COM方式提供,所以它的很多行为遵循COM规范。首先,要引入ADO的COM文件,它的位置一般在"C:/Program Files/Common Files/System/ado/msado15.dll"。

1. 引入ADO

打开预编译头文件StdAfx.h,写上引入声明:

#import "C:/Program Files/Common Files/System/ado/msado15.dll" no_namespace rename("EOF","adoEOF")

解释一下上句:no_namespace是指忽略命名空间,rename则是把ADO中的EOF重命名为adoEOF。命成什么名字无所谓,但注意声明中的名字要和代码中的名字一致。

2. 初始化

用ADO写代码前,要将COM初始化。常用手段是在代码前后加上CoInitialize(NULL)和CoUninitialize()。也可以用AfxOleInit()来初始化COM库。

3. 三个核心对象

ADO的3个核心对象是连接对象(_Connection)、命令对象(_Command)和记录集对象(_RecordSet)。其中连接对象是任何操作必须的。很多操作3个核心对象都可以完成。要实例化它们并使用它们提供的方法,不得不说到它们是一种智能指针(Smart Pointer)。在初始化或释放等操作时,它们是一个对象,用点操作符,其他大部分操作则使用“->”操作符。

4. 实例化

_ConnectionPtr pConn(__uuidof(Connection));

_RecordsetPtr pRec(__uuidof(Recordset));

_CommandPtr pCmd(__uuidof(Command));

如果上面不加参数,则需加上:

pConn.CreateInstance("ADODB.Connection");

pRec.CreateInstance("ADODB.Recordset");

pCmd.CreateInstance("ADODB.Command");

5. 连接数据库

连接数据库一般采取字符串连接。这个字符串的获取方法用了“不能说的秘密”,即任意新建一个txt文件,重命名为.x.udl。然后双击此文件,将出现“数据库连接属性”窗口。第一个标签页“提供程序”列出了所有数据库引擎,Access, SQL Server, Oracle等,选择后点下一步跳至第二个标签页“连接”,选择服务器名称栏可以填上服务器的IP地址,本机则可不填或填点号;填上数据库用户名和密码后就可以选择数据库了。点“测试连接”按钮,成功。确定。用记事本打开x.udl。将会看到它生成的连接字符串。如下:

"Provider=SQLOLEDB.1;Persist Security Info=False;User ID=sa;Password=123;Initial Catalog=cfdata"

此连接串中,Persist Security Info属性为True时表示在建立连接后仍然保存密码,一般取False即可。ID和Password属性只有在上述数据库属性对话框中勾选“允许保存密码”时才会有。自己可以手工添加。Cfdata是我的数据库名。

C++中连接代码如下:

pConn->ConnectionString="Provider=SQLOLEDB.1;Persist Security Info=False;User ID=sa;Password=123;Initial Catalog=cfdata";

6. 示例

有些数据库操作_Connection一个就能完全搞定。如update语句。因为它不需要返回的结果。如下:

pConn->ConnectionString="Provider=SQLOLEDB.1;Persist Security Info=False;User ID=sa;Password=123;Initial Catalog=cfdata";

pConn->Open("","","",adConnectUnspecified);   //打开连接。此处参数均已在上述字符串声明,故可为空

CString strSQL="update table1 set name=’Richard’ where id=1";

_pConn->Execute(_bstr_t(strSQL),NULL,adCmdText);

这里涉及强制类型转换。COM中的数据类型和常规(如MFC)类型一般都有对应,但需要转换。如上面的_bstr_t和CString。至于应该转换成什么类型,看VC环境中的提示即可(这里推荐大家加装Visual Assitant,使提示功能更完善)。

也有些操作需要返回记录集,如select语句。这里就至少需要_Connection和_Recordset两种核心对象,也可以用_Command执行之。下面展示同一操作用3种对象分别实现的代码。

(1)连接对象

CString strSQL="select * from table1";     //方法1

pRec=pConn->Execute(_bstr_t(strSQL),NULL,adCmdText);

(2)记录集对象

CString strSQL="select * from table1";           //方法2

pRec->Open(_variant_t(strSQL),(_variant_t)( (IDispatch*)pConn),adOpenDynamic,adLockOptimistic,adCmdText);

其中第二个参数(_variant_t)( (IDispatch*)pConn)指明活动连接,数据类型转换比较复杂,_variant_t是参数要求的类型,IDispath*则是_variant_t可强制转换类型类型。也可用下句:

pConnGetInterfacePtr();

(3) 命令对象

CString strSQL="select * from table1";         //方法3

pCmd->put_ActiveConnection((_variant_t)((IDispatch*)pConn));

pCmd->CommandText=_bstr_t(strSQL);

pRec=pCmd->Execute(NULL,NULL,adCmdText);

7. 数据使用

取得记录集后,将其中数据取出。用一个ListBox读取其中name字段数据。代码如下:

while(!pRec->adoEOF)

{

//_bstr_t类型可以视作COM类型字符串和MFC类型字符串之间的桥梁

CString str=LPSTR(_bstr_t(pRec->GetCollect("name")));

((CListBox*)GetDlgItem(IDC_LIST1))->AddString(str);

pRec->MoveNext();

}

上述代码中用到了adoEOF,要注意直接拷贝第三方代码时可能会被重命名为rsEOF等,此时则需作相应更改。另外,while循环中的MoveNext()也不要忘了,否则它就成了死循环了。字段值的获取及转换也可用下面方法:

_variant_t var=pRec->GetCollect("name");

var.ChangeType(VT_BSTR);

CString str=var.bstrVal;

8. 关闭与释放

用完相应对象后,需要关闭并释放之,代码如下:

pRec->Close();

pConn->Close();

pRec.Release();

pCmd.Release();

pConn.Release();

9. 错误捕获

数据库操作难免出现错误,连接串错误,SQL语句错误,或返回NULL你却硬要向表里塞(此错误可以在取出后用var.vt!=VT_NULL判断),所以我们需要把它们放到try…catch段中。ADO在捕获到错误后会抛出_com_error类型异常,我们可以这样做:

try

{

pConn->ConnectionString="Provider=SQLOLEDB.1;Persist Security Info=False;User ID=sa;Password=123;Initial Catalog=cfdata";

pConn->Open("","","",adConnectUnspecified);

…………   //代码省略

}

catch(_com_error& e)

{

AfxMessageBox(e.ErrorMessage());

AfxMessageBox(e.Description());

}

这里有个疑惑,在捕获错误后,e.ErrorMessage()和e.Description()中放着不同信息,有时前者说得清晰,有的后者说的清晰,搞不清楚,索性就都加上吧。最后,可以再加个catch(…),毕竟ADO之外的地方也可能发生错误。

这里,我还犯过一个错误,被它整了N久。我把_com_error& e写成了_com_error* e后面也对应改成->操作符,而且编译通过,结果一运行程序就崩溃,而且它不告诉我在哪出错,因为这时的错误是_com_error这时却对着_com_error*来捕获当然捕不到。这里&只是一个引用,写不写无所谓,*是万万不可地。(网上书上很多大师级代码都是用了*,误导啊)。

10. 其他接口

ADO中除了3个核心对象外,我们还应了解FieldsPtr、FieldPtr、StreamPtr等接口。例如上述示例中,我们可以用FieldsPtr的GetCount()方法获取其字段个数,用FieldPtr来接收具体字段等。二进制数据如图像文件等则会用到StreamPtr。

实例代码:

#include <iostream>
#include "vector" #import "C:\Program Files\Common Files\System\ado\msado15.dll" no_namespace rename("EOF","adoEOF")
using namespace std; int main(int argc, char* argv[])
{
CoInitialize(NULL);
_ConnectionPtr pConn(__uuidof(Connection));
_RecordsetPtr pRec(__uuidof(Recordset));
////或者采用以下方式:
//_ConnectionPtr pConn=NULL;
//_RecordsetPtr pRec=NULL;
//_CommandPtr pCmd=NULL;
//pConn->CreateInstance("ADODB.Connection");
//pRec->CreateInstance("ADODB.Recordset");
//pCmd->CreateInstance("ADODB.Command"); try
{
_bstr_t strConnect = "Provider=SQLOLEDB;Persist Security Info=True;\
User Id=sa;Password=123456;Initial Catalog=Test;Data Source=localhost";
//_bstr_t strConnect = "Provider=SQLOLEDB;Server=localhost;DataBase=Test;uid=sa;pwd=123456";
pConn->Open(strConnect,"","",adModeUnknown);
}
catch(_com_error &e)
{
cout<<"Initial failed!"<<endl;
cout<<e.Description()<<endl;
cout<<e.HelpFile()<<endl;
return 0;
} try
{
pRec = pConn->Execute("select * from CorrespondField",NULL,adCmdText);
if(!pRec->BOF)
{
pRec->MoveFirst();
}
else
{
cout<<"Data is empty!"<<endl;
return 0;
} vector<_bstr_t> column_name;
for(int i=0;i<pRec->Fields->GetCount();i++)
{
cout<<pRec->Fields->GetItem(_variant_t((long)i))->Name<<" ";
column_name.push_back(pRec->Fields->GetItem(_variant_t((long)i))->Name);
cout<<endl;
} while(!pRec->adoEOF)
{
for(vector<_bstr_t>::iterator Itr = column_name.begin();Itr!=column_name.end();Itr++)
{
if (pRec->GetCollect(*Itr).vt != VT_NULL)
{
cout<<(_bstr_t)pRec->GetCollect(*Itr)<<" ";
}
else
{
cout<<"NULL"<<endl;
}
}
pRec->MoveNext();
cout<<endl;
}
}
catch (_com_error &e)
{
cout<<e.Description()<<endl;
cout<<e.HelpFile()<<endl;
return 0;
} try
{
pRec->Close();
pConn->Close();
pRec->Release();
pConn->Release();
}
catch(_com_error &e)
{
cout<<e.Description()<<endl;
cout<<e.HelpFile()<<endl;
return 0;
} CoUninitialize();
return 0;
}

  

C++使用ADO连接数据库及其实例的更多相关文章

  1. 【转】Java JDBC对应C# ADO连接数据库之区别

    JDBC对应C#连接数据库之区别 之前一直在用java,最近因为找了.NET的工作,开始学习.NET. 今天也是查了好多资料,但是一直没有看到和JDBC之间的对比博文,开始也是一头雾水! 但是功夫不负 ...

  2. c# ado 连接数据库 六步曲

    建立连接分为六步:1.定义连接字符串,oracle 的连接字符串为: private static string connString = "Data Source=192.168.1.13 ...

  3. ADO连接数据库【msado15.dll】

    Microsoft ActiveX Data Objects (ADO) 注册表查看ADO版本:HKEY_LOCAL_MACHINE\Software\Microsoft\DataAccess下有Ve ...

  4. ADO 连接数据库,取到VT_DATE型日期转换成 int型

    DATE dt = vDate;(vDate是从数据库取出来的值,类型为_variant_t) COleDateTime odt = COleDateTime(dt); CString strdate ...

  5. Delphi 通过ADO连接数据库

  6. x64 win64编译环境下ADO链接Access数据库的问题解决

    原文链接地址:https://blog.csdn.net/HW140701/article/details/71077579 Win32编译环境下,用ADO数据库连接Access数据库一般都不会报错, ...

  7. ADO.NET教程(1)初识ado.net

    ADO.NET简介 ADO.NET使用到的类 需掌握的方法和属性 ado.net连接实例 ADO.NET的名称起源于ADO(ActiveX Data Objects),是一个COM组件库,用于在以往的 ...

  8. VC++下封装ADO类以及使用方法

    操作系统:windows 7软件环境:visual studio 2008 .Microsoft SQL 2005本次目的:介绍一个已经封装的ADO类,简单说明怎么导入使用 首先声明一下,这个封装的A ...

  9. JDBC连接数据库概述

    直接介绍JDBC连接数据库的流程及其原理 创建一个以JDBC连接数据库的程序,包含7个步骤 1.加载JDBC数据库驱动 在连接数据库之前,首先要加载想要连接的数据库的驱动,就是数据库厂商提供的jar包 ...

随机推荐

  1. DGA域名——可以每天只生成一个域名,因此最多存在365个 DGA域名;

    Mirai变种中的DGA 分享到: 发布时间:2016-12-12 16:02:57 作者:360网络安全研究院 投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿 那个导致美国断网 ...

  2. mongodb压缩——snappy、zlib块压缩,btree索引前缀压缩

    MongoDB 3.0 WiredTiger Compression and Performance One of the most exciting developments over the li ...

  3. mycat的事务支持情况

    中秋国庆一共12天,玩的有点嗨,完全没想工作的事情- -.回来赶紧补补.看了一下mycat关于事务的支持情况,做一下记录. 说mycat的事务支持之前,先说说XA协议,即分布式事务.指的是TM(事务管 ...

  4. POJ2274(后缀数组应用)

    Long Long Message Time Limit: 4000MS   Memory Limit: 131072K Total Submissions: 25272   Accepted: 10 ...

  5. CSS:CSS 网络安全字体组合

    ylbtech-CSS:CSS 网络安全字体组合 1.返回顶部 1. 常用的字体组合 font-family 属性应该使用若干种字体名称作为回退系统,以确保浏览器/操作系统之间的最大兼容性.如果浏览器 ...

  6. codevs-2235

    2235 机票打折 题目描述 Description .输入机票原价(3到4位的正整数,单位:元),再输入机票打折率(小数点后最多一位数字).编程计算打折后机票的实际价格(单位:元.计算结果要将个位数 ...

  7. 也谈Flash mmorpg地图问题【转】

    网上看一篇关于目前几个流行flash mmorpg地图实现的分析,这里也想说说自己的一些看法. 常见的三种方式:1.整图2.Tile元素拼装3.栅格化切片 整图 整图加载很好理解直接加载一张背景图.这 ...

  8. 洛谷 - P3935 - Calculating - 整除分块

    https://www.luogu.org/fe/problem/P3935 求: \(F(n)=\sum\limits_{i=1}^{n}d(i)\) 枚举因子\(d\),每个因子\(d\)都给其倍 ...

  9. layui icon样式1到7

    1: 2: 3: 4: 5: 6: 7:

  10. SQL 语句(原生)

    //查 //查询表里的所有数据 select * from 表名 //根据id等字段查询数据 select * from 表名 where 字段 = 值 or 字段 = 值 (例):select * ...