`
yangyou230
  • 浏览: 1649265 次
文章分类
社区版块
存档分类

ADO编程实用宝典

 
阅读更多

引入ADO类型库
Activex Objects Model首先是一组COM对象模型。所以通常我们需要引入其类型库,以下是引入类型库的语句
#import "c:/program files/common files/system/ado/msado15.dll" no_namespace raw_interfaces_only rename ("EOF","ADOEOF")
这里no_namespace 表示引入的类型不会放在名字空间里。raw_interfaces_only表示只使用COM的原始接口方法调用,而不使用包装接口。区别就是包装接口总是用异常的方式报错,而原始接口方法通过返回HRESULT值报告信息;同时,参数类型和数目略有区别。
编译器将生成msado15.tlh文件,该文件包含了ADO中的各种类型
创建与数据库的连接
首先我们声明连接对象。msado15.tlh文件中对于连接对象如下说明,
struct __declspec(uuid("00000514-0000-0010-8000-00aa006d2ea4"))
Connection;
// [ default ] interface _Connection
// [ default, source ] dispinterface ConnectionEvents
以下是创建连接对象的代码:
CComPtr<_Connection> pCon;
HRESULT hr=pCon.CoCreateInstance(__uuidof(Connection));
或者 HRESULT hr=pCon.CoCreateInstance(L"ADODB.Connection");
很多书上介绍使用_ConnectionPtr,实际上都是智能指针,只是个人习惯而已,这些智能指针类通过重载operator ->()函数暴露了接口方法。
然后使用udl文件和某数据库连接,我非常喜欢使用udl文件的方式,而不喜欢使用字符串与数据库连接,因为如果不小心差了一个空格,数据库连接就会出错,有时候错误一开始不会发生,但是说不定哪天就冒出来了。所以我的文章最后会给出数据库的连接字符串,但是不推荐使用。
pCon->put_ConnectionString(CComBSTR(L"File Name=c://fqw.udl"));
hr=pCon->Open(L"",L"",L"",NULL);
使用_Connection接口
Connection;
// [ default ] interface _Connection
// [ default, source ] dispinterface ConnectionEvents
通过msado15.tlh文件中的片断我们可以看出Connection对象实现了_Connection接口
查看_Connection接口的定义:
struct __declspec(uuid("00000534-0000-0010-8000-00aa006d2ea4"))
_ADO : IDispatch
{
//
// Raw methods provided by interface
//
virtual HRESULT __stdcall get_Properties (
/*[out,retval]*/ struct Properties * * ppvObject ) = 0;
};
struct __declspec(uuid("00000515-0000-0010-8000-00aa006d2ea4"))
Connection15 : _ADO
{
//
// Raw methods provided by interface
//
virtual HRESULT __stdcall get_ConnectionString (
/*[out,retval]*/ BSTR * pbstr ) = 0;
virtual HRESULT __stdcall put_ConnectionString (
/*[in]*/ BSTR pbstr ) = 0;
virtual HRESULT __stdcall get_CommandTimeout (
/*[out,retval]*/ long * plTimeout ) = 0;
virtual HRESULT __stdcall put_CommandTimeout (
/*[in]*/ long plTimeout ) = 0;
virtual HRESULT __stdcall get_ConnectionTimeout (
/*[out,retval]*/ long * plTimeout ) = 0;
virtual HRESULT __stdcall put_ConnectionTimeout (
/*[in]*/ long plTimeout ) = 0;
virtual HRESULT __stdcall get_Version (
/*[out,retval]*/ BSTR * pbstr ) = 0;
virtual HRESULT __stdcall Close ( ) = 0;
virtual HRESULT __stdcall Execute (
/*[in]*/ BSTR CommandText,
/*[out]*/ VARIANT * RecordsAffected,
/*[in]*/ long Options,
/*[out,retval]*/ struct _Recordset * * ppiRset ) = 0;
virtual HRESULT __stdcall BeginTrans (
/*[out,retval]*/ long * TransactionLevel ) = 0;
virtual HRESULT __stdcall CommitTrans ( ) = 0;
virtual HRESULT __stdcall RollbackTrans ( ) = 0;
virtual HRESULT __stdcall Open (
/*[in]*/ BSTR ConnectionString,
/*[in]*/ BSTR UserID,
/*[in]*/ BSTR Password,
/*[in]*/ long Options ) = 0;
virtual HRESULT __stdcall get_Errors (
/*[out,retval]*/ struct Errors * * ppvObject ) = 0;
virtual HRESULT __stdcall get_DefaultDatabase (
/*[out,retval]*/ BSTR * pbstr ) = 0;
virtual HRESULT __stdcall put_DefaultDatabase (
/*[in]*/ BSTR pbstr ) = 0;
virtual HRESULT __stdcall get_IsolationLevel (
/*[out,retval]*/ enum IsolationLevelEnum * Level ) = 0;
virtual HRESULT __stdcall put_IsolationLevel (
/*[in]*/ enum IsolationLevelEnum Level ) = 0;
virtual HRESULT __stdcall get_Attributes (
/*[out,retval]*/ long * plAttr ) = 0;
virtual HRESULT __stdcall put_Attributes (
/*[in]*/ long plAttr ) = 0;
virtual HRESULT __stdcall get_CursorLocation (
/*[out,retval]*/ enum CursorLocationEnum * plCursorLoc ) = 0;
virtual HRESULT __stdcall put_CursorLocation (
/*[in]*/ enum CursorLocationEnum plCursorLoc ) = 0;
virtual HRESULT __stdcall get_Mode (
/*[out,retval]*/ enum ConnectModeEnum * plMode ) = 0;
virtual HRESULT __stdcall put_Mode (
/*[in]*/ enum ConnectModeEnum plMode ) = 0;
virtual HRESULT __stdcall get_Provider (
/*[out,retval]*/ BSTR * pbstr ) = 0;
virtual HRESULT __stdcall put_Provider (
/*[in]*/ BSTR pbstr ) = 0;
virtual HRESULT __stdcall get_State (
/*[out,retval]*/ long * plObjState ) = 0;
virtual HRESULT __stdcall OpenSchema (
/*[in]*/ enum SchemaEnum Schema,
/*[in]*/ VARIANT Restrictions,
/*[in]*/ VARIANT SchemaID,
/*[out,retval]*/ struct _Recordset * * pprset ) = 0;
};
struct __declspec(uuid("00000550-0000-0010-8000-00aa006d2ea4"))
_Connection : Connection15
{
//
// Raw methods provided by interface
//
virtual HRESULT __stdcall Cancel ( ) = 0;
};
_Connection接口继承了Connection15接口,Connection15 又继承了_ADO。_ADO接口是绝大多数ADO接口的基接口。
使用_Connection接口执行SQL语句
CComBSTR SQL(L"DELETE FROM [15]");
hr=pCon->Execute(SQL,NULL,adCmdText|adExecuteNoRecords,NULL);
Execute也可以执行查询语句返回结果记录集,第三个参数取消adExecuteNoRecords第四个参数将_Recordset的指针地址传递进来即可。
MDAC2.0开始引入了连接池的概念,ODBC中使用了connection pooling,OLEDB和ADO中使用了resource pooling。
ADO中,如果连接字符串相同,但是动态属性值不一样(比如:PROMPT),MDAC仍然会创建两个用户身份。连接池的用户身份和操作系统的登陆账号不是一回事,它取决于连接字符串和任何在连接对象打开之前的设置的属性值。如果客户程序使用同样的用户身份和连接属性对同一个数据存储请求连接对象,连接池中的合适的连接对象将被激活。连接对象被释放后会返回连接池中,经过60秒不被激活,会被自动销毁。
ADO的连接对象实际上内部使用数据源代理对象,如果在连接对象关闭状态下设置连接对象的属性,则属性值将缓存在本地的数据源代理对象中。当打开连接对象时会检查resource pooling中是否有和代理请求的相同的数据源代理对象,如果有则使用池中的,否则创建。所有resource pooling只存放数据源代理对象,不会存放其他的资源。MDAC2.5版本之前不可以修改resource pooling中的数据源代理对象实效时间。
ADO默认会启用resource pooling。但是如果客户程序不能保持至少一个连接对象,则
连接池不会生存。这里可以考虑使用COM+对象池保存连接对象。
打开的连接对象一定要通过Close关闭,不要忘记,否则连接对象不能返回resourse pooling中。将导致性能降低。
不过最终决定不再使用连接对象,应该调用Release方法释放。这是COM的规则。
_Connection::put_ConnectionString方法用来设置连接字符串,但是注意以下几点:
1)_Connection::Open打开时如果第一个参数非空,该参数也可以设置或者覆盖ConnectionString,
2)如果使用UDL文件,如前面所举的例子,_Connection::get_ConnectionString获取到的不是UDL文件名,而是UDL文件的属性,比如:
“Provider=SQLOLEDB.1;
Password=sa;
Persist Security Info=True;
User ID=sa;
Initial Catalog=ff;
Data Source=FREEBIRD;
Use Procedure for Prepare=1;
Auto Translate=True;
Packet Size=4096;
Workstation ID=FREEBIRD;
Use Encryption for Data=False;
Tag with column collation when possible=False“
3)连接字符串使用”参数=参数值;”方式构成,ADO支持五种参数,其他由数据提供者提供:Provider 、File Name、Remote Provider、Remote Server、URL。ADO只是将其他参数直接传递给数据提供者,自己并不做任何处理。
COM+对象池保存Connection对象
近一年多来我本人几乎从来不在客户程序中调用ADO,这与从事的编程工作多为系统开发有关。系统开发讲究服务器资源的负荷不能超过极限,讲究客户调用服务快进快出等。在微软的平台上开发DNA系统一定要借助于COM+。所以我重点讨论COM+中如何运用ADO编程,这就是本文与一般的ADO文章的最大不同。
我将在COM+对象CMIS类中维护一个局部变量CComPtr<_Connection> m_pCon;我准备将该COM+对象配置为支持对象池和JITA。关于COM+对象池和JITA可以参考我的另一篇文章《COM+编程研究之对象池、JITA》,这里不做说明。
由于_Connection接口指针每次当方法调用后会被放入对象池中,而下一次调用它的客户将来自另一个COM+上下文,所以必须经过轻量列集,而不能直接使用m_pCon,所以我们需要
1)在GIT中保存_Connection接口;
2)在每次方法调用时从GIT中散集该接口;
3)在每次方法调用后释放该接口;
4)在最后对象被释放的时候要将GIT中保存的接口指针删除。
请参考下面的源代码示例:
创建Connection对象,并将获取的_Connection接口指针保存到GIT中,m_Cookie用来以后从GIT中取出该接口指针。
HRESULT FinalConstruct()
{
HRESULT hr=m_pCon.CoCreateInstance(__uuidof(Connection));
if(hr!=S_OK)
return hr;
hr=m_pCon->put_ConnectionString(CComBSTR(L"File Name=c://海塘.udl"));
if(hr!=S_OK)
return hr;
hr=m_pCon->Open(L"",L"",L"",NULL);
if(hr!=S_OK)
return hr;
CComPtr<IGlobalInterfaceTable> pGTable;
hr=pGTable.CoCreateInstance(CLSID_StdGlobalInterfaceTable);
if(hr!=S_OK)
return hr;
hr=pGTable->RegisterInterfaceInGlobal(m_pCon.p,__uuidof(_Connection),&m_Cookie);
m_pCon.Release();
return hr;
}
方法调用时从GIT中列集_Connection指针:
HRESULT CMIS::Activate()
{
HRESULT hr = GetObjectContext(&m_spObjectContext);
if (hr!=S_OK)
return hr;
CComPtr<IGlobalInterfaceTable> pGTable;
hr=pGTable.CoCreateInstance(CLSID_StdGlobalInterfaceTable);
if(hr!=S_OK)
return hr;
hr=pGTable->GetInterfaceFromGlobal(m_Cookie,__uuidof(_Connection),(void**)&m_pCon.p);
if(hr!=S_OK)
return hr;
return S_OK;
}
设定方法调用后总是返回到对象池
BOOL CMIS::CanBePooled()
{
return TRUE;
}
方法调用后将当前_Connection接口释放
void CMIS::Deactivate()
{
m_pCon.Release();
m_spObjectContext.Release();
}
我们如何让我们的COM+对象CMIS总是拥有至少一个ADO连接对象呢?很简单,将COM+对象池下限设为1。
列集_Recordset接口指针到客户程序:
话题才刚刚开始。我打算用以下方法进行测试,CMIS对象提供一个方法GetShuJuZiDian从ff数据库中的数据字典表中读入所有数据,该方法将把_Recordset接口指针传递出去,客户需要自行导入ADO15.DLL中的类型库信息才能使用。该_Recordset是从Connection对象的Execute方法获取的,因此是只读并且向前移动的,这样正好,因为我不想让客户获得过大的权力。
IDL如下:
interface IMIS : IDispatch{
[id(1), helpstring("方法将传递一个_Recordset接口指针,传递出去的记录集对象是只读并且只能向前移动")] HRESULT GetShuJuZiDian([out]IUnknown** pRec);
};
代码实现如下:
STDMETHODIMP CMIS::GetShuJuZiDian(IUnknown** pRec)
{
//The returned Recordset object is always a read-only, forward-only cursor.
CComBSTR SQL(L"select * from 数据字典表");
HRESULT hr=m_pCon->Execute(SQL,NULL,adCmdText,(_Recordset**)pRec);
return hr;
}
客户端调用代码如下:
#include "stdafx.h"
#import "haitangmis.tlb" no_namespace raw_interfaces_only named_guids
#include <iostream>
using namespace std;
#include <atlstr.h>
int _tmain(int argc, _TCHAR* argv[])
{
::CoInitialize(NULL);
CComPtr<IMIS> pMIS;
HRESULT hr=pMIS.CoCreateInstance(CLSID_MIS);
IUnknown* pIUn=NULL;
hr=pMIS->GetShuJuZiDian(&pIUn);
VARIANT_BOOL vResult;
CComPtr<_Recordset> pRec;
hr=pIUn->QueryInterface(__uuidof(_Recordset),(void**)&pRec.p);
hr=pRec->get_ADOEOF(&vResult);
CComPtr<Fields> pFields;
CComPtr<Field> pField;
CComVariant Value;
while(vResult==VARIANT_FALSE)
{
hr=pRec->get_Fields(&pFields.p);
hr=pFields->get_Item(CComVariant(0),&pField);//
CComBSTR Name;
pField->get_Name(&Name);
cout<<CString(Name)<<endl;
hr=pField->get_Value(&Value);
hr=Value.ChangeType(VT_BSTR);
cout<<CString(Value.bstrVal)<<endl;
hr=pRec->MoveNext();
pField.Release();
pFields.Release();
hr=pRec->get_ADOEOF(&vResult);
}
hr=pRec->Supports(adMovePrevious,&vResult);
hr=pRec->Supports(adUpdate,&vResult);
pRec.Release();
pIUn->Release();
pMIS.Release();
::CoUninitialize();
int x;
cin>>x;
return 0;
}
freebird
5/16/2005
分享到:
评论

相关推荐

    Visual C++程序开发范例宝典(光盘) 第八部分

    Visual C++程序开发范例宝典配套光盘,因大小受限,所以分成8部分上传,必须全部下载才能正常解压! 第1章 窗体与界面设计 1.1 菜单应用实例 实例001 在系统菜单中添加菜单项 实例002 带图标的程序菜单 实例003...

    ASP.NET 程序开发范例宝典 (第三版)PART 1 源代码

    本书紧密围绕编程者在编程中遇到的实际问题和开发中应该掌握的技术,全面介绍了ASP.NET进行程序开发的各方面技术和技巧。全书分为22章(其中第22章综合实例放在配套光盘中),内容包括搭建ASP.NET开发环境,页面设计...

    PHP程序开发范例宝典III

    个实例,每个实例都突出实用性,绝大部分实例都体现了PHP编程人员在实际项目开发过程中总结出的经验技巧。  《PHP程序开发范例宝典》内容充实,实例丰富,特别适于PHP编程人员和广大计算机爱好者学习开发使用,也...

    ASP.NET程序开发范例宝典4

    本书紧密围绕编程者在编程中遇到的实际问题和开发中应该掌握的技术,全面介绍了ASP.NET进行程序开发的各方面技术和技巧。全书分为20章,内容包括搭建ASP.NET开发环境、HTML开发与实践、CSS样式与JavaScript脚本应用...

    ASP.NET程序开发范例宝典5

    本书紧密围绕编程者在编程中遇到的实际问题和开发中应该掌握的技术,全面介绍了ASP.NET进行程序开发的各方面技术和技巧。全书分为20章,内容包括搭建ASP.NET开发环境、HTML开发与实践、CSS样式与JavaScript脚本应用...

    ASP.NET程序开发范例宝典2

    本书紧密围绕编程者在编程中遇到的实际问题和开发中应该掌握的技术,全面介绍了ASP.NET进行程序开发的各方面技术和技巧。全书分为20章,内容包括搭建ASP.NET开发环境、HTML开发与实践、CSS样式与JavaScript脚本应用...

    ASP.NET程序开发范例宝典3

    本书紧密围绕编程者在编程中遇到的实际问题和开发中应该掌握的技术,全面介绍了ASP.NET进行程序开发的各方面技术和技巧。全书分为20章,内容包括搭建ASP.NET开发环境、HTML开发与实践、CSS样式与JavaScript脚本应用...

    Delphi开发范例宝典目录

    实例295 对ADO控件的无数据库操作 389 第9章 SQL技术 391 9.1 通用查询 392 实例296 SQL语句的应用方法 392 实例297 SQL语句的模糊查询 393 实例298 高级Like语句 394 实例299 多功能查询过滤器 396 ...

    C#程序开发范例宝典(第2版).part08

    精选570个典型范例,全面覆盖实用和热点技术,涉及面广,实用性强源于实际项目开发,帮助读者短时间掌握更多实用技术,提高编程水平范例经过精心编排,重点、难点突出,易学易懂书后附录提供快速索引,即查、即学、...

    C#程序开发范例宝典(第2版).part12

    精选570个典型范例,全面覆盖实用和热点技术,涉及面广,实用性强源于实际项目开发,帮助读者短时间掌握更多实用技术,提高编程水平范例经过精心编排,重点、难点突出,易学易懂书后附录提供快速索引,即查、即学、...

    Visual C++ 程序开发范例宝典 源码 光盘 part2

    8.1 连接数据库 cc实例205 使用 ODBCcDSN连接SQLcServer数据库 cc实例206 用ADO动态连接数据库 cc实例207c连接Oracle数据库 8.2 添加数据 cc实例208 利用INSERT语句批量插入数据 cc实例209 利用...

    Visual C++程序开发范例宝典(PDF扫描版).part2

     cc实例206 用ADO动态连接数据库   cc实例207c连接Oracle数据库   8.2 添加数据   cc实例208 利用INSERT语句批量插入数据   cc实例209 利用SELECTcINTO生成临时表   8.3 更新数据   cc实例210 ...

    21天学通ASP.NET 光盘

    40小时多媒体语音视频教学,源代码和电子教案(PPT)1000余页编程参考宝典电子书(免费赠送)。 内容推荐 本书是ASP.NET的入门教程。ASP.NET 3.5是微软精心打造的新型的软件开发平台。该平台是在.NET2.0的基础上发展...

    21天学通ASP.NET 光盘part02

    40小时多媒体语音视频教学,源代码和电子教案(PPT)1000余页编程参考宝典电子书(免费赠送)。 内容推荐 本书是ASP.NET的入门教程。ASP.NET 3.5是微软精心打造的新型的软件开发平台。该平台是在.NET2.0的基础上发展...

    21天学通ASP.NET 光盘part01

    40小时多媒体语音视频教学,源代码和电子教案(PPT)1000余页编程参考宝典电子书(免费赠送)。 内容推荐 本书是ASP.NET的入门教程。ASP.NET 3.5是微软精心打造的新型的软件开发平台。该平台是在.NET2.0的基础上发展...

    21天学通ASP.NET 光盘part04

    40小时多媒体语音视频教学,源代码和电子教案(PPT)1000余页编程参考宝典电子书(免费赠送)。 内容推荐 本书是ASP.NET的入门教程。ASP.NET 3.5是微软精心打造的新型的软件开发平台。该平台是在.NET2.0的基础上发展...

    21天学通ASPNET 光盘part05

    40小时多媒体语音视频教学,源代码和电子教案(PPT)1000余页编程参考宝典电子书(免费赠送)。 内容推荐 本书是ASP.NET的入门教程。ASP.NET 3.5是微软精心打造的新型的软件开发平台。该平台是在.NET2.0的基础上发展...

    21天学通ASP.NET 光盘part06

    40小时多媒体语音视频教学,源代码和电子教案(PPT)1000余页编程参考宝典电子书(免费赠送)。 内容推荐 本书是ASP.NET的入门教程。ASP.NET 3.5是微软精心打造的新型的软件开发平台。该平台是在.NET2.0的基础上发展...

Global site tag (gtag.js) - Google Analytics