ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

使用 m_pRecordset->GetRecordCount();获取记录数不准确的问题总结:从 msado15.dll 到 TaoToken 的排查路径

使用 m_pRecordset->GetRecordCount();获取记录数不准确的问题总结:从 msado15.dll 到 TaoToken 的排查路径 1. 从一次“记录数永远不对”的排查说起GetRecordCount 返回 -1 到底卡在哪如果你在用 VC6 或 VS 系列写 MFC 程序通过 ADO 访问 Access2000 的.mdb文件然后调用m_pRecordset-GetRecordCount()想拿到记录条数结果发现它要么返回-1要么返回一个明显偏大、偏小的值那你不是一个人。这个坑我踩过而且踩得挺深。先说清楚GetRecordCount是什么。它是 ADORecordset对象的一个属性用来返回当前记录集中的记录数量。听起来很简单但它的返回值高度依赖两个东西游标类型CursorType和游标位置CursorLocation。如果游标是只进游标adOpenForwardOnly那RecordCount基本就是废的返回-1是常态因为驱动根本没打算帮你数总数。而 Access2000 这种老数据库配合不同版本的msado15.dll行为差异会更大。适合谁看这篇正在维护老 MFC 工程、需要兼容 Access2000、又不想大改数据访问层的同学。核心检索词就是GetRecordCount、msado15.dll、access2000、adOpenStatic、RecordCount。我会把连接字符串、游标配置、三步验证动作都写成可复制的片段你照着改就能定位到底是游标问题、DLL 版本问题还是 SQL 本身的问题。典型场景是这样的你要在保存数据前判断某个ProductNum是否已存在存在就更新不存在就插入。代码大概长这样strSql.Format(SELECT * FROM TestData WHERE ProductNum%s, productNum); hbr m_pRecordset-Open(_bstr_t(strSql), m_pConnection.GetInterfacePtr(), adOpenDynamic, adLockOptimistic, adCmdText); RecordCount m_pRecordset-GetRecordCount();问题就出在这里adOpenDynamic是动态游标很多 Provider 对动态游标的RecordCount支持很差返回-1或者一个不可信的值。你换成adOpenStatic有时也不灵因为游标位置没设对或者msado15.dll版本和 Access2000 的 Jet 引擎不匹配。下面我按排查路径一步步拆。2. TaoToken 前置准备把模型对话和接入文档先跑通在正式改代码之前我建议先把排查思路理清楚而不是盲目替换 DLL。这里可以借助 TaoToken 的模型对话能力把你遇到的报错、连接字符串、游标参数贴进去让它帮你分析可能的原因。TaoToken 是一个聚合多种大模型的 API 平台你可以用它来辅助排查这类老代码问题也可以用它做代码润色和文档整理。具体怎么用先打开模型对话页面地址是https://taotoken.net/api如果你需要看接入文档了解 Base URL、Key、Model ID 怎么填可以访问https://taotoken.net/api-keys以及文档页https://taotoken.net/doc注意TaoToken 的 API 地址是https://taotoken.net/api这个不加 UTM 参数直接用于代码里的 Base URL。而官网首页带 UTM 的是https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content为什么要先做这一步因为排查GetRecordCount不准的问题往往需要对比多个方案换游标、换 DLL、换 SQL 写法。你可以把每种方案的代码片段丢给模型让它帮你检查参数是否写对。比如你写adOpenStatic但CursorLocation还是默认的adUseServer模型会提醒你静态游标通常要配合客户端游标才能可靠返回RecordCount。另外如果你长期要做这类老工程维护和 Agent 辅助编码可以考虑 Coding Plan地址是https://taotoken.net/coding-plan它适合需要长期编码辅助的场景。不过这篇的重点还是排查路径TaoToken 在这里的角色是帮你快速验证思路、生成对比代码而不是替代你的调试过程。前置准备还包括一件事确认你的工程里msado15.dll的引入路径。很多老工程在StdAfx.h里写的是#import C:\Program Files\Common Files\System\ado\msado15.dll no_namespace rename(EOF,adoEOF)而有的工程为了避开系统目录权限问题会把 DLL 拷到别的路径再引入。这个路径差异后面会直接影响GetRecordCount的行为。3. 可复制配置连接字符串、游标类型与 msado15.dll 引入片段这一节给你可以直接抄的配置。先看连接字符串。Access2000 用的是 Jet 引擎Provider 要写Microsoft.Jet.OLEDB.4.0CString ConnectString; ConnectString.Format(ProviderMicrosoft.Jet.OLEDB.4.0;Data Source%s, lpszFile); hbr m_pConnection-Open((_bstr_t)ConnectString, , , adModeUnknown);连接对象创建后关键一步是设置CursorLocation。如果你想让RecordCount可靠通常要设成客户端游标m_pConnection-CursorLocation adUseClient;然后是 Recordset 的打开方式。把adOpenDynamic换成adOpenStatic并且锁类型用adLockReadOnly或adLockOptimistic都行但游标必须是静态或键集hbr m_pRecordset-Open(_bstr_t(strSql), m_pConnection.GetInterfacePtr(), adOpenStatic, adLockOptimistic, adCmdText);如果你用的是m_pSetCRecordset 派生类那要在Open之前设置m_pSet-CursorType adOpenStatic; m_pSet-CursorLocation adUseClient;接下来是msado15.dll的引入。原始工程里可能是这样#import C:\Program Files\Common Files\System\ado\msado15.dll no_namespace rename(EOF,adoEOF)如果你怀疑是 Win7 自带的msado15.dll对 Access2000 支持不好可以从一个确认正常的旧系统里拷贝一份放到独立目录然后改引入路径#import C:\Program Files\Common Files\msado15.dll no_namespace rename(EOF,adoEOF)注意这里路径变了DLL 文件也换了。这个操作在原始案例里是解决问题的关键一步。但我要提醒你替换系统 DLL 有风险建议只把旧 DLL 放在工程私有目录通过引入路径指定不要直接覆盖系统目录里的文件。为了让你对照参数我列一个表参数推荐值说明ProviderMicrosoft.Jet.OLEDB.4.0Access2000 专用CursorLocationadUseClient客户端游标RecordCount 更可靠CursorTypeadOpenStatic静态游标支持 RecordCountLockTypeadLockOptimistic按需选择不影响计数CommandTypeadCmdText直接执行 SQL 文本还有一个细节如果你的 SQL 是SELECT *而表里字段很多静态游标会把整个结果集拉到客户端内存开销大。如果只是判断存在性更好的做法是用SELECT COUNT(*)这个后面验证环节会讲。4. 验证请求与成功结果三步动作确认 RecordCount 是否可信改完配置别急着下结论按下面三步验证。第一步切换游标类型对比。先用adOpenDynamic跑一次打印GetRecordCount()再换成adOpenStaticadUseClient跑一次打印同样的值。如果第一次返回-1或异常大值第二次返回正确条数那问题就在游标配置。long nCount m_pRecordset-GetRecordCount(); TRACE(RecordCount %ld\n, nCount);第二步对比SELECT COUNT(*)。单独开一个 Recordset执行strSql SELECT COUNT(*) FROM TestData WHERE ProductNum...;拿到数据库层面的真实条数和GetRecordCount()的结果比对。如果两者不一致说明游标返回的计数不可信如果一致说明配置生效了。第三步记录实际遍历条数。用while(!m_pRecordset-adoEOF)循环遍历自己累加计数最后和GetRecordCount()对比。这一步最笨但最可靠能排除游标缓存导致的偏差。long nReal 0; while (!m_pRecordset-adoEOF) { nReal; m_pRecordset-MoveNext(); } TRACE(Real count %ld\n, nReal);成功的结果应该是GetRecordCount()返回值等于SELECT COUNT(*)的结果也等于实际遍历条数。如果三者一致说明游标、DLL、SQL 都没问题。如果GetRecordCount()还是不对但实际遍历条数正确那说明你的业务逻辑可以改用遍历计数或者继续排查 DLL 版本。我实测下来在 Win7 上如果用的是系统自带的msado15.dll配合 Access2000adOpenStatic有时仍然返回偏大的值。换成旧版 DLL 后GetRecordCount()才和SELECT COUNT(*)对上。所以第三步的遍历计数非常关键它能帮你判断到底是计数属性坏了还是数据本身有问题。5. 本篇常见错排查401、local proxy failed、reading choices、OAuth 报错对照虽然这篇主要讲 ADO 和 Access2000但你在用 TaoToken 辅助排查时可能会遇到一些接入层的报错。这里列几个常见的方便你对照。401 Unauthorized。通常是 API Key 没填对或者 Key 过期。检查你的请求头里Authorization: Bearer 你的Key是否正确。如果你在代码里把 Key 写死注意别把空格或换行带进去。local proxy failed。这个报错一般出现在本地网络配置或代理设置上。如果你在代码里设置了 HTTP 代理但代理不可用就会报这个。检查你的WinINet或WinHttp配置确认没有残留的代理设置。reading choices 相关报错。如果你在调用模型接口时返回体里choices字段读取失败通常是响应格式和预期不符。检查你的 JSON 解析代码确认choices[0].message.content路径正确。OAuth 报错。如果你用的是需要 OAuth 的接入方式报错通常是 token 过期或 scope 不对。重新走一遍授权流程确认回调地址和 Key 匹配。回到 ADO 本身还有一个常见错m_pRecordset-MoveLast()在记录不存在时直接报错。原始案例里提到过这个。原因是空记录集上调用MoveLast会触发adErrNoCurrentRecord。所以不要用MoveLast来“逼”出RecordCount正确做法还是设对游标。另外如果你在StdAfx.h里改了msado15.dll的引入路径记得清理工程重新编译否则可能还是链接到旧的类型库。清理Debug和Release目录下的.tlh、.tli文件再重新生成。还有一个坑CursorLocation必须在Open之前设置连接对象和记录集对象都是。如果你在Open之后才改不生效。6. 语义一致 CTA把排查思路沉淀成可复用的接入配置排查完GetRecordCount不准的问题你会发现核心就三件事游标类型、游标位置、DLL 版本。把这三件事固定成一套可复用的配置以后遇到类似的老数据库访问问题直接套用就行。如果你想把这类排查过程沉淀成文档或者让模型帮你生成对比代码可以用 TaoToken 的模型对话https://taotoken.net/api需要管理 Key 就去 API Keys 页面https://taotoken.net/api-keys接入细节看文档https://taotoken.net/doc长期做编码辅助和 Agent 开发可以了解 Coding Planhttps://taotoken.net/coding-plan最后给你一个实用技巧在工程里封装一个GetRealRecordCount函数内部先用SELECT COUNT(*)拿真实条数再决定是否打开记录集。这样既避开了GetRecordCount的坑又不会因为静态游标拉取全表而浪费内存。对于 Access2000 这种老库SELECT COUNT(*)的执行速度通常比打开静态游标快得多。
返回列表