已阅读5页,还剩6页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1 1 ADOADO 简介简介 ADO 是 Microsoft 为最新和最强大的数据访问范例 OLE DB 而设计的 是一个便于使用的应用程序层接口 ADO 使您能够编写应用程序以通过 OLE DB 提供者访问和操作数据库服务器中的数据 ADO 最主要的优点是易于使用 速 度快 内存支出少和磁盘遗迹小 ADO 在关键的应用方案中使用最少的网络流量 并且在前端和数据源之间使用最少 的层数 所有这些都是为了提供轻量 高性能的接口 之所以称为 ADO 是用了一个比较熟悉的暗喻 OLE 自动化接 口 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 从前一直以为用从前一直以为用 ADOADO 编写的程序可以做到大致通用 但是经过这次项目 让我明白 你必须事先确定好应用将要编写的程序可以做到大致通用 但是经过这次项目 让我明白 你必须事先确定好应用将要 使用的数据库 并且了解其特性 否则最终你的程序肯定会折磨你 就像本次项目 我为了方便 一开始使用了使用的数据库 并且了解其特性 否则最终你的程序肯定会折磨你 就像本次项目 我为了方便 一开始使用了 accessaccess 数据库 并且顺利的开发完程序 然后当我移植到数据库 并且顺利的开发完程序 然后当我移植到 ORACLEORACLE 的时候 出现了许多莫名其妙的问题 如时间取不出的时候 出现了许多莫名其妙的问题 如时间取不出 来 来 selectselect 语句无效 记录集不更新 程序莫名其妙异常等问题 然而该程序用语句无效 记录集不更新 程序莫名其妙异常等问题 然而该程序用 MSMS SQLSERVERSQLSERVER 也是正常的 我相当郁也是正常的 我相当郁 闷 为什么会这样呢 实际后来我明白 一部分原因是闷 为什么会这样呢 实际后来我明白 一部分原因是 ORACLEORACLE 特性所致 另一部分原因是特性所致 另一部分原因是 ADOADO 所致 所致 2 2 通用的开发步骤 通用的开发步骤 1 1 引入 ADO 库文件 使用 ADO 前必须在工程的 stdafx h 头文件里用直接引入符号 import 引入 ADO 库文件 以使编译器能正确编译 代 码如下所示 加入 ADO 支持库 import c program files common files system ado msado15 dll no namespace rename EOF adoEOF 加载的位置如下图 这行语句声明在工程中使用 ADO 但不使用 ADO 的名字空间 并且为了避免常数冲突 将常数 EOF 改名为 adoEOF 现在不需添加另外的头文件 就可以使用 ADO 接口了 2 2 初始化 OLE COM 库环境 必须注意的是 ADO 库是一组 COM 动态库 这意味应用程序在调用 ADO 前 必须初始化 OLE COM 库环境 在 MFC 应 用程序里 一个比较好的方法是在应用程序主类的 InitInstance 成员函数里初始化 OLE COM 库环境 BOOL CMyInstanceAppApp InitInstance if AfxOleInit 这就是初始化 COM 库 AfxMessageBox OLE 初始化出错 return FALSE 初始化 COM 库也可以用如下代码 HRESULT hr 初始化 Com 库 hr CoInitialize NULL if FAILED hr AfxMessageBox T 初始化 Com 库失败 3 3 ADO 接口简介 ADO 库包含三个基本接口 ConnectionPtr 接口 CommandPtr 接口和 RecordsetPtr 接口 ConnectionPtr 接口返回一个记录集或一个空指针 通常使用它来创建一个数据连接或执行一条不返回任何结果 的 SQL 语句 如一个存储过程 使用 ConnectionPtr 接口返回一个记录集不是一个好的使用方法 对于要返回记录的 操作通常用 RecordserPtr 来实现 而用 ConnectionPtr 操作时要想得到记录条数得遍历所有记录 而用 RecordserPtr 时不需要 CommandPtr 接口返回一个记录集 它提供了一种简单的方法来执行返回记录集的存储过程和 SQL 语句 在使用 CommandPtr 接口时 你可以利用全局 ConnectionPtr 接口 也可以在 CommandPtr 接口里直接使用连接串 如果你只 执行一次或几次数据访问操作 后者是比较好的选择 但如果你要频繁访问数据库 并要返回很多记录集 那么 你 应该使用全局 ConnectionPtr 接口创建一个数据连接 然后使用 CommandPtr 接口执行存储过程和 SQL 语句 RecordsetPtr 是一个记录集对象 与以上两种对象相比 它对记录集提供了更多的控制功能 如记录锁定 游标 控制等 同 CommandPtr 接口一样 它不一定要使用一个已经创建的数据连接 可以用一个连接串代替连接指针赋给 RecordsetPtr 的 connection 成员变量 让它自己创建数据连接 如果你要使用多个记录集 最好的方法是同 Command 对象一样使用已经创建了数据连接的全局 ConnectionPtr 接口 然后使用 RecordsetPtr 执行存储过程和 SQL 语句 3 3 通用数据库连接串及区别 通用数据库连接串及区别 通常情况下 ORACLE 有两种连接方式 第一种方式 第一种方式 OLEOLE DBDB ProviderProvider forfor OracleOracle from from Microsoft Microsoft The Microsoft OLE DB Provider for Oracle allows ADO to access Oracle databases strConnect T For more information see Microsoft OLE DB Provider for Oracle 第二种方式 第二种方式 OLEOLE DBDB ProviderProvider forfor OracleOracle from from Oracle Oracle For Standard security strConnect T For a Trusted connection OS Authenticated connect setting user ID to strConnect T OS Authenticated connect using OSAuthent strConnect T Note Note For more information see Oracle Provider for OLE DB Developer s Guide 重要提示 重要提示 第一种连接方式不支持第一种连接方式不支持 select from 表表 语句的表中带有时间戳和语句的表中带有时间戳和 blob 字段 即如果某表中带有时间戳或者字段 即如果某表中带有时间戳或者 blob 字段 则字段 则 select 语句会出错 改进的办法为将所有字段写出来 如果遇上时间戳字段 则进行如下处理 语句会出错 改进的办法为将所有字段写出来 如果遇上时间戳字段 则进行如下处理 select 字段 1 字段 2 to char 时间字段 yyyy mm dd hh24 mi ss 时间字段别名 字段 3 from tablename 如果遇上如果遇上 blob 字段 可以用字段 可以用 select where 语句找到记录 然后用语句找到记录 然后用 updae 语句更新 语句更新 第二种方式语句支持第二种方式语句支持 select 语句 在程序上可以做到不少简化 语句 在程序上可以做到不少简化 常见错误 常见错误 网上不少朋友说在用网上不少朋友说在用 ORACLE 的时候 记录集的时候 记录集 open 出错 实际情况大致有两种 一种就是连接字符串用出错 实际情况大致有两种 一种就是连接字符串用 了第一种 另一种方式就是定义表结构的时候里面用到了了第一种 另一种方式就是定义表结构的时候里面用到了 ORACLE 的关键字段 的关键字段 常见疑问 有些人问常见疑问 有些人问 Provider 为什么有时候是为什么有时候是 OraOLEDB Oracle 有时候是 有时候是 OraOLEDB Oracle 1 其实这个问题比 其实这个问题比 较简单 用较简单 用 regedit 打开注册表查询一下即可 如果你的机器上两种描述都有 则用其中任何一个即可 如果仅仅有一打开注册表查询一下即可 如果你的机器上两种描述都有 则用其中任何一个即可 如果仅仅有一 种名称 那么程序中使用注册表中描述的名称即可 不过需要指出的是 如果你的机器上使用的不是企业版的种名称 那么程序中使用注册表中描述的名称即可 不过需要指出的是 如果你的机器上使用的不是企业版的 ORACLE 而是 而是 10g EXPRESS 则当该数据库安装了客户端后 有时候会修改注册表中连接串描述 导致连接字符串 则当该数据库安装了客户端后 有时候会修改注册表中连接串描述 导致连接字符串 无效 但是不安装客户端 仅仅安装服务器 程序就不会出问题 无效 但是不安装客户端 仅仅安装服务器 程序就不会出问题 4 记录集的常用 记录集的常用 open 方式及区别方式及区别 关于记录集的描述 网上已经有很多详细的描述 在此不再累赘 需要指出的是 那些 open 的参数在其他数据库 中 似乎从记录集的结果中看 区别不是很大 但是在 ORACLE 中 区别则较大 甚至会影响我们的程序 说明如下 m pKnowRecordset CreateInstance uuidof Recordset 第一步 应该将记录集实例化 CString sSql sSql SELECT FROM InstanceInfo WHERE PropType 1 第二步 生成相应的 select 语句 try 第三步 打开记录集 m pKnowRecordset Open variant t sSql theApp m ptrConnection GetInterfacePtr adOpenDynamic 也可以改为 adOpenStatic adLockOptimistic adCmdText catch com error e AfxMessageBox e ErrorMessage if m pParaRecordset State m pParaRecordset Close 第四步 使用结束应该关闭记录集 m pParaRecordset NULL 上述是记录集常见使用步骤 大家应该比较熟悉 但要特别申明如下 但要特别申明如下 1 如果 如果 open 方式使用的是方式使用的是 adOpenDynamic 则如果程序中增加了记录并且 则如果程序中增加了记录并且 m pKnowRecordset Update 后 该记后 该记 录尽管会实时的添加到录尽管会实时的添加到 ORACLE 数据库中 但是数据库中 但是 m pKnowRecordset 中并没有新添加的记录 只有使用中并没有新添加的记录 只有使用 m pKnowRecordset Requery 0 语句才能将新增加的记录添加到语句才能将新增加的记录添加到 m pKnowRecordset 网上很多人说记录集的记录没 网上很多人说记录集的记录没 有增加到有增加到 list 中 或者只有重新登录系统才能看到新增加的记录即属于此种情况 中 或者只有重新登录系统才能看到新增加的记录即属于此种情况 2 如果 如果 open 方式使用的是方式使用的是 adOpenStatic 则中 仅仅使用 则中 仅仅使用 m pKnowRecordset Update 即可将增加的记录实时的反即可将增加的记录实时的反 应到应到 m pKnowRecordset 中 中 3 上述情况在其他数据库中没有太大区别 上述情况在其他数据库中没有太大区别 因此如果大家如果在因此如果大家如果在 ORACLE 中 在记录集中出现问题 不妨首先调整一下中 在记录集中出现问题 不妨首先调整一下 open 参数 不要马上修改主程序 或许参数 不要马上修改主程序 或许 你会得到意外惊喜 你会得到意外惊喜 5 oracle 对对 NULL 的个性处理以及的个性处理以及 ado 中对中对 update 的影响的影响 假设我们再 ORACLE 数据库中已经定义了 TEST 表 表中有两个字段 字段分别为 A1 NUMBER A2 VARCHER2 10 事先我们在数据库中增加一个记录 1 aa 并且仅一条记录 下面的代码可以重现错误 以下是测试以下是测试 NULL 的代码的代码 CString sSql SELECT FROM TEST try m pKnowRecordset Open variant t sSql theApp m ptrConnection GetInterfacePtr adOpenStatic adLockOptimistic adCmdText catch com error e AfxMessageBox e ErrorMessage m pKnowRecordset MoveFirst 假设数据库中仅仅一条记录 切记假设数据库中仅仅一条记录 切记 variant t var var m pKnowRecordset GetCollect A2 if var vt VT NULL 如果数据库中该条记录的如果数据库中该条记录的 A2 字段有数据字段有数据 CString strTemp LPCSTR bstr t var CString m sA2 m sA2 m pKnowRecordset PutCollect A2 variant t m sA2 m pKnowRecordset Update 第一次第一次 update m pKnowRecordset Requery 0 没有这句话绝对在第二个没有这句话绝对在第二个 update 处出错处出错 m sA2 哈哈哈哈 m pKnowRecordset PutCollect A2 variant t m sA2 m pKnowRecordset Update 该处可能出错该处可能出错 else 如果数据库中该条记录的如果数据库中该条记录的 A2 字段没有数据字段没有数据 CString m sA2 m sA2 m pKnowRecordset PutCollect A2 variant t m sA2 m pKnowRecordset Update 第一次第一次 update m pKnowRecordset Requery 0 没有这句话绝对在第二个没有这句话绝对在第二个 update 处出错处出错 m sA2 m pKnowRecordset PutCollect A2 variant t m sA2 m pKnowRecordset Update 该处可能出错该处可能出错 测试测试 NULL 代码结束代码结束 为什么会出现上述错误呢 在第二个的更新语句执行中 在代码中检测到错误 核心问题的原因在于为什么会出现上述错误呢 在第二个的更新语句执行中 在代码中检测到错误 核心问题的原因在于 Oracle 引擎引擎 将空的字符串转换为将空的字符串转换为 NULL 而不是 而不是 ADO 记录集存储一个零长度缓冲区为空字符串 记录集存储一个零长度缓冲区为空字符串 因此 因此 如果大家程序中遇上一条记录多次更新出错的情况 如果大家程序中遇上一条记录多次更新出错的情况 应该首先考虑对应该首先考虑对 空字符串的处理多加一些逻辑判断 空字符串的处理多加一些逻辑判断 或者更新或者更新 update 的时候增加的时候增加 Requery 上述问题在其他数据库中比较正常 上述问题在其他数据库中比较正常 6 timestamp 字段的建议字段的建议 时间戳在 ORACLE 中是比较个性的问题 在数据库中如果有 timestamp 字段 会给我们程序移植 移植到其他数 据库 带来诸多问题 建议大家慎用 或者将时间改为字符串 或者将时间改为 number 1 如果是时间戳 应该进行如下程序的修改 插入 insert into tablename 时间字段名 values sysdate 检索 select to char 时间字段 yyyy mm dd hh24 mi ss 时间字段别名 from t table 来获得 时间格式可以自己 定 如果是想将某个时间 insert 到这个字段就用 to date insert into 表名 字段 values to date 时间值 yyyy mm dd hh24 mi ss 时间的默认值可以在字段中设置 sysdate 2 将时间戳改为字符串的问题比较简单 仅仅需要注意字符串格式一定要统一 长度一定要定长 3 将时间改为将时间改为 number 建议采用的方法建议采用的方法 需要用到的核心函数 time 函数原型 time t time time t timer 函数功能 得到机器的日历时间或者设置日历时 间 函数返回 机器日历时间 参数说明 timer NULL 时得到机器日历时间 timer 时间数值时 用于设置日历时间 time t 是一个 long 类型 取数据然后以时间格式展现 var m pKnowRecordset GetCollect PropDateTime if var vt VT NULL LONGLONG nTime LONGLONG var time t tt time t nTime CTime cTime new CTime tt CString sTime cTime Format Y m d H M S m ctrlListBase SetItemText i 7 sTime delete cTime 将数据保存到数据库 time t ltime time LONGLONG nTime LONGLONG ltime m pKnowRecordset PutCollect PropDatetime variant t nTime 相关 time 的一些详细说明如下 头文件中说明了一些用于处理日期和时间的类型和函数 其中的一部分函数用于处理当地时间 因为时区 等原因 当地时间与日历时间可能不相同 clock t 和 time t 是两个用于表示时间的算术类型 而 struct tm 则用于存放 日历时间的各个成分 tm 的各个成员的用途及取值范围如下 int tm sec 秒 0 61 int tm min 分 0 59 int tm hour 时 0 23 int tm mday 日 1 31 int tm mon 月 从 1 月开始 0 11 int tm year 年 从 1900 年开始 int tm wday 星期 从周日开始 0 6 int tm yday 天数 从 1 月 1 日开始 0 365 int tm isdst 夏令时标记 其中 tm isdst 在使用夏令时时其值为正 在不使用夏令时时其值为 0 如果该信息不能使用 其值为负 clock include clock t clock void 返回程序自开始执行到目前为止所占用的处理机时间 如果处理机时间不可使用 那么返回 1 clock CLOCKS PER SEC 是以秒为单位表示的时间 time include time t time time t tp 返回当前日历时间 如果日历时间不能使用 则返回返回当前日历时间 如果日历时间不能使用 则返回 1 如果 如果 tp 不为不为 NULL 那么同时把返回值赋给 那么同时把返回值赋给 tp difftime include double difftime time t time2 time t time1 返回 time2 time1 的值 以秒为单位 mktime include time t mktime struct tm tp 将结构 tp 中的当地时间转换为 time t 类型的日历时间 并返回该时间 如果不能转换 则返回 1 asctime include char asctime const struct tm tp 将结构 tp 中的时间转换成如下所示的字符串形式 day month date hours minutes seconds year n 0 如 Fri Apr 15 15 14 13 2005 n 0 返回指向该字符串的指针 字符串存储在可被其他调用重写的静态对象中 ctime include char ctime const time t tp 将 tp 中的日历时间转换为当地时间的字符串 并返回指向该字符串指针 字符串存储在可被其他调用重写的静态 对象中 等价于如下调用 asctime localtime tp gmtime include struct tm gmtime const time t tp 将 tp 中的日历时间转换成 struct tm 结构形式的国际标准时间 UTC 并返回指向该结构的指针 如果转换失败 返回 NULL 结构内容存储在可被其他调用重写的静态对象中 localtime include struct tm localtime const time t tp 将 tp 中的日历时间转换成 struct tm 结构形式的本地时间 并返回指向该结构的指针 结构内容存储在可被其他调 用重写的静态对象中 strftime include size t strftime char s size t smax const char fmt const struct tm tp 根据 fmt 的格式说明把结构 tp 中的日期与时间信息转换成指定的格式 并存储到 s 所指向的数组中 写到 s 中的 字符数不能多于 smax 函数返回实际写到 s 中的字符数 不包括 0 如果产生的字符数多于 smax 则返回 0 fmt 类似于 printf 中的格式说明 它由 0 个或多个转换规格说明与普通字符组成 普通字符原封不动的拷贝到 s 中 每个 c 按照下面所描述的格式用与当地环境相适应的值来替换 转换规格列表如下 返回当前日历时间 如果日历时间不能使用 则返回返回当前日历时间 如果日历时间不能使用 则返回 1 如果 如果 tp 不为不为 NULL 那么同时把返回值赋给 那么同时把返回值赋给 tp 格式格式 说明说明 a 一星期中各天的缩写名一星期中各天的缩写名 A 一星期中各天的全名一星期中各天的全名 b 缩写月份名缩写月份名 B 月份全名月份全名 c 当地时间和日期表示当地时间和日期表示 d 用整数表示的一个月中的第几天用整数表示的一个月中的第几天 01 31 H 用整数表示的时用整数表示的时 24 小时制 小时制 00 23 I 用整数表示的时用整数表示的时 12 小时制 小时制 01 12 j 用整数表示的一年中各天用整数表示的一年中各天 001 366 m 用整数表示的月份用整数表示的月份 01 12 M 用整数表示的分用整数表示的分 00 59 p 与与 AM PM 对应的当地表示方法对应的当地表示方法 S 用整数表示的秒用整数表示的秒 00 61 U 用整数表示一年中的星期数用整数表示一年中的星期数 00 53 将星期日看作为每周的第一天 将星期日看作为每周的第一天 w 用整数表示一周中的各天用整数表示一周中的各天 0 6 星期日为 星期日为 0 W 用整数表示一年中的星期数用整数表示一年中的星期数 00 53 将星期一看作为每周的第一天 将星期一看作为每周的第一天 x 当地日期表示当地日期表示 X 当地时间表示当地时间表示 y 不带公元的年不带公元的年 00 99 Y 完整年份表示完整年份表示 Z 时区名字时区名字 可获得时可获得时 本身本身 7 blob 字段存取字段存取 1 BLOB 数据的保存数据的保存 BLOB 类型的数据无法用普通的方式进行存储 我们需要使用 AppendChunk 函数 AppendChunk 包含在 Field 对象中 原型如下 HRESULT AppendChunk const variant t 从函数原型中可以看到关键的问题是我们需把二进制数据赋值给 VARIANT 类型
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 大班数学课件送给恶猫的礼物
- 2024美食城招商合同范本
- 两公司买卖合同纠纷一案引发的对钢材加价款性质的探究及对“执行难”的思考-毕业论文
- 2024个人伤害保险合同
- 辐射4代码大全整合
- 高端样板间开盘活动
- 2024店面转让合同协议书样本
- 2024企业产权合同范文
- 2024家庭装饰的合同范本
- 2024广告销售代理合同范本
- 一年级科学上册教案《做个小侦探》
- 工艺管道安装规范及验收标准重点课件
- 2023年燕舞集团有限公司招聘笔试模拟试题及答案解析
- 100句英文记7000雅思单词带单词解释和音标
- 劳务投标书技术标
- 送达地址确认书(诉讼类范本)
- 《马克思主义发展史》第五章 马克思列宁主义在苏联的发展及曲折
- ASME-第Ⅸ卷焊接工艺评定,焊工技能评定
- 初三家长会物理学科
- 调度通信系统搬迁方案
- 师旷论学 课件
评论
0/150
提交评论