OLE DB是一种非常具有发展潜力的数据库访问技术,它首先基于COM技术,以COM规范为基础建立数据库访问接口,成为介于数据库应用和数据源之间的一种通用数据访问标准;其次,OLE DB能够访问的数据源不再受到限制,OLE DB通过OLE DB服务器将数据源透明化。从6.0版本开始,Visual C++提供了对OLE DB的全面支持。
8.1 OLE DB原理
8.1.1 OLE DB与ODBC
在Visual C++之前的数据库编程,通常都采用ODBC实现数据库的访问。ODBC是访问数据库的一个底层标准,数据库供应商常常需要编写ODBC驱动程序,以支持客户对数据库的访问。虽然ODBC仍然是一个不断发展的技术,但是ODBC在以下两个方面无法达到目标:
ODBC只能访问关系型数据源,而现在有许多数据源,包括E-Mail、Word文档、文本、Internet连接与传输等等,是ODBC无法访问的。
ODBC不能用于专门访问特定的数据,因此使得ODBC不够强大,为了追求标准,效率受到了严重影响。
OLE DB成功地解决了上述两个问题。OLE DB为用户提供了访问不同类型的数据源的一种通用方法,它作为数据源和应用程序的中间层,允许应用程序以相同的接口访问不同类型的数据源。OLE DB由一套通过COM访问数据源的ActiveX接口组成,它提供一种访问数据的统一手段,开发人员在开发时,不必考虑数据源的类型。
8.1.2 OLE DB的结构
OLE DB由客户(Consumer,也称为应用程序)和服务器(Provider,又称为提供者程序)组成。客户是指任何一个使用了OLE DB接口的系统或者应用程序,其中包括OLE DB本身,而服务器是指所有提供OLE DB接口的软件组件。
OLE DB客户是使用数据的应用程序,它通过OLE DB接口对数据提供者的数据进行访问和控制。在大多数情况下,前端的数据库应用开发都属于客户程序的开发。
OLE DB服务器是提供OLE DB接口的软件组件,根据提供的内容可以将服务器分成数据提供程序和服务器提供程序。数据提供程序拥有数据并将这些数据以表的形式存放,例如关系型DBMS、存储管理器、电子表格和ISAM数据库等。服务器提供程序不拥有数据,但是可以通过利用OLE DB接口建立一些提供服务的组件。从某种意义上来说,服务组件既是客户又是服务器。
对于一个完整的数据库应用程序来说,客户和数据提供程序都是必不可少的。然而服务提供程序却是可以省略的。当客户需要对数据库进行操作时,他并非直接对数据源发出指令,而是通过OLE接口与数据源进行交互,数据服务器从数据源取得所要查询的数据时,以表格的形式将其提供给接口,再由客户将数据从接口取出并使用。在这些操作中,客户和数据服务器都不必知道对方的具体应用,而只需要对接口进行操作,从而简化了程序设计。
8.1.3 OLE DB的优越性
OLE DB是一种基于COM的全新数据库开发技术,它具有如下优点:
广泛的应用领域
以往的数据库访问技术,包括ODBC、DAO等,都只能访问关系型数据库,而OLE DB被设计成可以访问任何格式的文件,其中当然包括关系型和非关系型的数据源,以及用户自定义的文件格式,用户只需要对所使用的数据源产生自己的数据提供程序,OLE DB客户程序就可以透明地访问到它们。
简洁的开发过程
OLE DB的对象组件和接口已经定义了数据提供程序所需要的接口,Visual C++ 6.0也为此提供了OLE DB模板,可以很方便地产生一个OLE DB应用程序框架。OLE DB为建立服务提供程序提供了一系列功能,这些功能可以大大简化数据提供程序的设计。由于数据使用程序并不需要知道当前数据提供程序的细节,因此它只需要使用OLE DB的接口即可完成程序设计。由于接口的标准性,数据使用程序可以被用到任何提供了数据提供程序的数据源,使得OLE DB程序具有良好的移植性。
可靠的稳定性
OLE DB应用程序是基于COM接口的应用程序,它继承了COM接口的所有特性。COM模型具有良好的稳定性,COM与COM之间只要遵循规定的接口,可以很容易地进行通信,所有组件和接口共同工作,组成一个稳定的应用程序。OLE DB的各个对象都提供了错误对象和错误接口,可以由应用程序截获错误,对其进行适当处理,从而提高了应用软件的稳定性。
高效的数据访问
作为一个组件数据库管理系统,OLE DB通过将数据库的功能划分为客户和服务器两个方面,提供了比传统数据库更高的效率。由于数据使用者通常只需要数据库管理的一部分功能,OLE DB将这些功能分离开来,减少了用户方面的资源开销,同时减少了服务器方面的负担。
综上所述,由于提供了灵活的接口和优越的性能,OLE DB必定成为数据库开发的方向。
8.1.4 OLE DB对象
OLE DB的每一个组件都是一个COM对象,每一个组件都输出一系列的接口。OLE DB由下列组件组成:
枚举器
枚举器用于搜寻可用的数据源和其它的枚举器。如果客户没有指定所使用的枚举器,则可以使用枚举器来寻找,一般通过搜寻注册表来发现相应的数据源。该对象包括如下接口:
CoType TEnumerator{
[mandatory] IParseDisplayName;
[mandatory] ISourceRowset;
[mandatory] IDBInitialize;
[mandatory] IDBProperties;
[mandatory] ISupportErrorInfo;
}
数据源对象
数据源对象包含与数据源(DBMS或者文件系统)连接的方法,此对象中含有环境变量、连接信息、用户信息、用户口令等信息。使用数据源对象可以产生会话。该对象包括如下接口:
CoType TDataSource{
[mandatory] interface IDBCreateSession;
[mandatory] interface IDBInitialize;
[mandatory] interface IDBProperties;
[mandatory] interface IPersist;
[mandatory] interface IConnectionPointContainer;
[mandatory] interface IDBAsynchStatus;
[optional] interface IDBDataSourceAdmin;
[optional] interface IDBInfo;
[optional] interface IPersistFile;
[optional] interface ISupportErrorInfo;
}
会话
会话为事务处理提供了上下文环境,它可以被显式或者隐式地执行。一个数据源对象可以拥有多个会话,而通过会话又能够生成事务、命令和行集。该对象的接口如下:
CoType TSession{
[mandatory] interface IGetDataSource
[mandatory] interface IOpenRowset
[mandatory] interface ISessionProperties;
[optional] interface IDBCreateCommand;
[optional] interface IDBSchemaRowset;
[optional] interface IIndexDefinition;
[optional] interface ITableDefinition;
[optional] interface ITransactionJion;
[optional] interface ITransactionLocal;
[optional] interface ITransaction;
[optional] interface ITransactionObject;
[optional] interface ISupportErrorInfo;
}
事务对象
事务对象用于管理数据库的事务,将多个操作合并为一个单一的事务处理。该对象缓存了对数据源的改变,使应用程序有机会选择提交或者回退以往的操作。事务能够提高应用访问数据库的性能,但是OLE DB数据服务器并不要求支持该对象。该对象包括如下接口:
CoType TTransaction{
[mandatory] interface IConnectionPointContainer;
[mandatory] interface ITransaction;
[optional] interface ISupportErrorInfo;
}
命令对象
命令对象用于对数据源发送文本命令。对于支持SQL的数据源,SQL命令同命令对象一起执行,包括两种数据定义语言和产生行集对象的查询,对于其它不支持SQL的数据源,命令对象给数据源发送其它类型的文本命令。但是对于数据提供程序来说,不一定必须支持这个命令对象。一个单独的会话能够产生多个命令对象。该对象包括如下接口:
CoType TCommand{
[mandatory] interface IAccessor;
[mandatory] interface IColumnsInfo;
[mandatory] interface ICommand;
[mandatory] interface ICommandProperties;
[mandatory] interface ICommandText;
[mandatory] interface IConvertType;
[optional] interface IColumnsRowset;
[optional] interface ICommandPrepare;
[optional] interface ICommandWithParameters;
[optional] interface ISupportErrorInfo;
}
行集
行集以表的形式显示数据,其中索引就是一种特殊的行集。行集可以从会话或者命令对象产生。如果数据提供程序不支持命令对象,则行集可以由数据提供程序直接产生,直接产生行集是每一个数据提供程序的基本功能。根据数据提供程序所提供的功能,行集对象可以完成更新、插入、删除等操作。该对象包括如下接口:
CoType TRowset{
[mandatory] interface IAccessor;
[mandatory] interface IColumnsInfo;
[mandatory] interface IConvertType;
[mandatory] interface IRowset;
[mandatory] interface IRowsetInfo;
[mandatory] interface IChapteredRowset;
[optional] interface IColumnsRowset;
[optional] interface IConnectionPointContainer;
[optional] interface IDBAsynchStatus;
[optional] interface IRowsetChange;
[optional] interface IRowsetFind;
[optional] interface IRowsetIdentity;
[optional] interface IRowsetIndex;
[optional] interface IRowsetLocate;
[optional] interface IRowsetRefresh;
[optional] interface IRowsetScroll;
[optional] interface IRowsetUpdate;
[optional] interface IRowsetView;
[optional] interface ISupportErrorInfo;
}
错误对象
错误对象中封装了访问数据提供程序时发生的错误,它可以由任何OLE DB对象的任何接口产生。错误对象中含有关于错误的附加信息,包括一个可选的定制错误对象,通过它也能够获得扩展的返回码和状态信息。该对象包括如下接口:
CoType TError{
[mandatory] interface IErrorRecords;
}
如果用户不能确定数据源的位置,可以先使用枚举器寻找数据源,在找到数据源以后,就可以使用它来生成一个会话,这个会话允许用户对数据进行访问,或者以行集的形式,或者以命令的形式。
图8-1展示了OLE DB应用程序的对象流程。
图8-1 OLE DB应用程序对象流程
图8-2 OLE DB的客户模板体系结构
8.1.5 OLE DB客户模板结构
OLE DB客户模板支持OLE DB1.1版本的标准,它使实现一个0级OLE DB代码质量、客户所需要标写的代码量达到最少。该模板具有如下优点:
易于使用OLE DB所提供的功能。
易于与ATL和MFC集成。
提供了数据参数绑定和列绑定的简单模型。
在编程时能够使用C/C++数据类型。
OLE DB的客户模板体系结构如图8-2所示。
由图可以看出,OLE DB的客户模板体系结构由数据源支持类、用户记录类、行集和绑定类以及表和命令支持类4部分构成。
8.1.6 OLE DB客户模板类
为了能更好的使用OLE DB客户模板进行应用程序设计,首先必须熟悉OLE DB的客户模板类。根据功能,OLE DB的客户模板类分成7种:会话类、存取器类、行集类、命令类、属性类、书签类以及错误类。
会话类
会话类包括CDataSource类、CEnmmerator类、CSession类和CEnmmeratorAccessor类。
1. CDataSource类
CDataSource类对应于OLE DB的数据源对象,代表服务器与数据源的连接。在单个连接上可以拥有多个数据库会话,其中的每一个会话都由CSession对象表示。调用CDataSource类的Open方法可以建立同数据源的连接。
2. CEnmmerator类
CEnmmerator类对应于OLE DB的枚举器对象,能够检索可用的数据源和枚举器信息。CEnmmerator通过ISourcesRowset接口来获得包含所有数据源和枚举器描述的行集,用户可以直接通过该类得到ISourcesRowset数据。
3. CSession类
CSession类对应于OLE DB的会话对象,代表单个数据库访问会话。要从CDataSource对象创建一个新的CSession对象,需要首先调用CDataSource对象的Open方法建立同数据源的连接,创建CSession对象的方法也是调用CSession对象的Open方法。该类还提供了事务处理函数,用户调用StartTransaction函数开始一个事务处理操作,调用Commit或者Abort函数提交或者回退这个事务处理。
4. CEnmmeratorAccessor类
CEnmmeratorAccessor类被CEnmmerator类用来访问来自枚举器行集的数据,这个行既包括从当前枚举器中可见的数据源和枚举器。
存取器类
存取器类包括CAccessorBase类、CAccessor类、CDynamicAccessor类、CDynamicParameterAccessor类和CManualAccessor类。
1. CAccessorBase类
CAccessorBase类是所有存取器类的基类,所有存取器的OLE DB模板都是从该类中派生出来的。CAccessorBase类允许一个行集管理多个存取器,它还提供了对参数和输出的绑定。
2. CAccessor类
CAccessor类用于静态绑定到数据源的记录,使用该存取器类时,必须事先知道数据源的结构。当一个记录被静态绑定到数据源时,该记录包含一个缓冲区。该类支持单个行集上的多个存取器。当知道数据源的结构时可以使用该存取器。
3. CDynamicAccessor类
CDynamicAccessor类所代表的存取器可以在运行时被创建,它基于行集的列信息。当不知道数据源的结构时,可以使用CDynamicAccessor类检索数据。该类将创建并管理缓冲区,使用GetValue方法从缓冲区里读取数据。
4. CDynamicParameterAccessor类
在不知道命令类型时,可以使用CDynamicParameterAccessor类进行数据存取。如果服务器支持ICommandWithParameters接口,则该类就通过调用这个接口读取参数信息。该类与CDynamicAccessor类类似,但是它所获得的是参数信息。该类也能够创建并管理缓冲区,通过调用GetParam和GetParamType方法可以从缓冲区里读取列的信息。
5. CManualAccessor类
CManualAccessor类具有同时处理列和命令的能力,利用这个类,能够使用服务器可转换的数据类型。该类代表了为将来设计而使用的存取器类型,使用该类能够通过运行时函数调用指定参数和输出列。
行集类
行集类包括CRowset类、CBulkRowset类、CAccessorRowset类、CArrayRowset类和CRestrictions类。
1. CRowset类
CRowset类用于处理、建立和检索行数据。在OLE DB中,行集为应用程序操作数据所用的对象。CRowset类封装了OLE DB行集对象和一些相关的接口,并为操作行集数据提供了成员函数。
2. CBulkRowset类
CBulkRowset类用于批量读取和处理行,通过单个函数调用可检索多个行句柄。
3. CAccessorRowset类
CAccessorRowset类封装一个行集和相关的存取器。
4. CArrayRowset类
CArrayRowset类用于以数组形式访问行集中的元素。
5. CRestrictions类
CRestrictions类用于为纲要行集指定限制条件。
命令类
命令类包括:CCommand类、CTable类、CMultipleResults类、CNoMultipleResults类、CNoAccessor类和CNoRowset类。
1. CCommand类
CCommand类用于设置和执行一个基于参数的OLE DB命令,如果只需要打开一个简单的行集,则应该使用CTable类。
2. CTable类
CTable类用于访问一个不带参数的简单行集。
3. CMultipleResults类
CMultipleResults类用于将CCommand类的TMultiple参数设置为TRUE。
4. CNoMultipleResults类
CMultipleResults类用于将CCommand类的TMultiple参数设置为FALSE。
5. CNoAccessor类
CNoAccessor类用于将CCommand类的TAccessor参数设置为FALSE。
6. CNoRowset类
CNoAccessor类用于将CCommand类的TRowset参数设置为FALSE。
属性类
属性类包括:CDBPropIDSet类和CDBPropSet类。
1. CDBPropIDSet类
CDBPropIDSet类用于传递一个包含客户请求的属性信息的属性ID数组。
OLE DB客户用DBPROPIDSET结构来传递一组客户要得到的属性信息的属性标识。在DBPROPIDSET结构中被标识的属性属于一个属性集合。CDBPropIDSet类继承了DBPROPIDSET结构并添加了一个构造函数,用于初始化关键字段和AddPropertyID方法。
2. CDBPropSet类
CDBPropSet类用于设置服务器属性。
OLE DB服务器和客户用DBPROPSET结构来传递DBPROP结构数组。每一个DBPROP结构代表了可以被设置的单个属性。CDBPropSet类继承了DBPROP结构并添加了一个构造函数,用于初始化关键字段数据成员和AddProperty方法。
书签类
OLE DB里客户模板的书签类是指CBookMark类,它被用于以索引的形式在行集中访问数据。
错误类
OLE DB里客户模板的错误类是指CDBErrorInfo类,它用于检索OLE DB的出错信息。这个类提供了使用OLE DB的IErrorRecords接口进行OLE DB出错处理的支持。这个接口向用户返回一个或者多个错误记录。调用GetErrorRecords方法可以得到一个出错记录数,然后调用GetAllErrorInfo方法检索每一条出错记录的信息。