尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

ADO Recordset 的 RecordCount 总是 -1?从 CursorType 与 CursorLocation 配置说起

ADO Recordset 的 RecordCount 总是 -1?从 CursorType 与 CursorLocation 配置说起 1. 为什么你的 Recordset.RecordCount 永远是 -1如果你在用 ASP、VB6 或者 VBScript 操作 ADO取rs.RecordCount时发现它恒等于 -1rs.PageCount也是 -1分页直接没法做——这不是你的代码写错了而是 ADO 游标机制在按设计行事。RecordCount 返回 -1 的本质含义是当前这个 Recordset 使用的游标类型不支持行数统计提供程序无法提前知道总共有多少条记录。很多人第一反应是绕过去比如再发一条select count(*) from table或者用do while not rs.EOF循环累加计数。这两种办法在只需要一个总数时能凑合但一旦你要用AbsolutePage、PageCount、PageSize做分页循环计数就彻底失效了因为你没法在只向前游标上跳页。真正要解决的是游标配置问题而不是绕过它。RecordCount 能不能用取决于两个属性CursorType游标类型和CursorLocation游标位置。默认情况下 ADO 用的是只向前游标adOpenForwardOnly这种游标为了性能只给你一条一条往下读不维护总行数所以 RecordCount 只能是 -1。把游标换成静态游标adOpenStatic或键集游标adOpenKeysetRecordCount 就能返回真实行数。而 CursorLocation 决定了游标是服务器端算还是客户端算客户端游标adUseClient几乎总是支持 RecordCount。这篇文章会从连接字符串、游标参数、最小验证代码三个层面给你一套可以直接复制运行的排查骨架帮你确认到底是游标类型选错了还是提供程序本身不支持行数统计。2. 前置准备连接字符串与 ADO 常量在动手改游标之前先把连接和常量理顺。ADO 里那些数字参数0、1、2、3非常容易记混建议直接用 ADO 常量代码可读性会好很多。在 ASP 或 VB6 里你需要引用Microsoft ActiveX Data Objects 2.x Library然后就能用adOpenStatic、adUseClient这类常量。下面是一个标准的 Access 连接字符串骨架注意Provider和Data Source的写法 Access 2003/2007 (.mdb) 连接字符串 connStr ProviderMicrosoft.Jet.OLEDB.4.0; _ Data Source Server.MapPath(data.mdb) ; _ Persist Security InfoFalse; 如果数据库带密码追加 Jet OLEDB:Database Password connStr connStr Jet OLEDB:Database Passwordyourpwd;如果是 SQL Server连接字符串换成 OLE DB 提供程序connStr ProviderSQLOLEDB.1; _ Data Source127.0.0.1; _ Initial CatalogTestDB; _ User IDsa;Passwordyourpwd;连接建立之后不要急着OpenRecordset。先把游标位置定下来再决定游标类型顺序很重要因为CursorLocation必须在 Recordset 打开之前设置打开之后再改是无效的。注意CursorLocation和CursorType都是 Recordset 打开前可读写、打开后只读的属性。很多人把rs.CursorLocation adUseClient写在rs.Open后面结果当然不生效RecordCount 还是 -1。3. 可复制配置CursorType 与 CursorLocation 组合骨架这一节给你一套可以直接抄的配置骨架。核心思路是先设 CursorLocation再设 CursorType最后 Open。下面这段代码同时适用于 ASP 和 VB6Dim conn, rs Set conn Server.CreateObject(ADODB.Connection) conn.Open connStr Set rs Server.CreateObject(ADODB.Recordset) 第一步设置游标位置为客户端 rs.CursorLocation adUseClient 值 3 第二步设置游标类型为静态游标 rs.CursorType adOpenStatic 值 3 第三步打开记录集锁类型用只读即可 rs.Open SELECT * FROM Products, conn, adOpenStatic, adLockReadOnly 此时 RecordCount 应该返回真实行数 Response.Write 总记录数 rs.RecordCount如果你习惯用rs.Open sql, conn, 游标类型, 锁类型这种四参数写法等价配置是rs.CursorLocation adUseClient rs.Open SELECT * FROM Products, conn, 3, 1 参数3adOpenStatic参数4adLockReadOnly这里有个关键点当CursorLocation adUseClient时ADO 只支持adOpenStatic。就算你传了adOpenDynamic提供程序也不会报错而是悄悄用最接近的静态游标替代。所以客户端游标 静态游标是最稳的组合RecordCount 和 PageCount 都能正常返回。下面这张表帮你快速对照各游标类型对 RecordCount 的支持情况CursorType常量值RecordCount 支持适用场景adOpenForwardOnly0返回 -1单向遍历性能最高adOpenKeyset1返回真实计数需要看到他人更新adOpenDynamic2取决于提供程序完全动态开销大adOpenStatic3返回真实计数分页、报表、只读展示锁类型LockType不影响 RecordCount它只决定记录集能不能改。分页场景用adLockReadOnly值 1就够了别为了“可写”去选悲观锁那会拖慢打开速度。4. 最小验证代码确认游标是否支持行数统计光看配置还不够你需要一段能跑起来、能打印结果的验证代码确认当前游标到底支不支持 RecordCount。下面这段 ASP 代码可以直接放到 IIS 里跑% Dim conn, rs Set conn Server.CreateObject(ADODB.Connection) conn.Open ProviderMicrosoft.Jet.OLEDB.4.0;Data Source Server.MapPath(data.mdb) Set rs Server.CreateObject(ADODB.Recordset) rs.CursorLocation adUseClient rs.CursorType adOpenStatic rs.Open SELECT * FROM Products, conn, adOpenStatic, adLockReadOnly Response.Write CursorLocation rs.CursorLocation br Response.Write CursorType rs.CursorType br Response.Write RecordCount rs.RecordCount br Response.Write PageCount rs.PageCount br Response.Write PageSize rs.PageSize br rs.Close conn.Close Set rs Nothing Set conn Nothing %跑出来如果RecordCount是正数说明游标配置成功。如果还是 -1把CursorLocation改成adUseServer再试一次对比两次输出。服务器端游标下adOpenStatic通常也能返回计数但某些 OLE DB 提供程序尤其是老版本的 Jet 或第三方驱动在服务器端就是不支持这时只能靠客户端游标兜底。再给一个 VB6 的验证片段逻辑一样只是输出用Debug.PrintDim rs As ADODB.Recordset Set rs New ADODB.Recordset rs.CursorLocation adUseClient rs.Open SELECT ProductID FROM Products, _ ProviderMicrosoft.Jet.OLEDB.4.0;Data SourceD:\nwind.mdb, _ adOpenStatic, adLockReadOnly Debug.Print RecordCount rs.RecordCount实测下来客户端静态游标在 Access 和 SQL Server 上都能稳定返回 RecordCount。唯一要注意的是客户端游标会把整个结果集拉到本地内存数据量特别大几十万行以上时内存占用会明显上升这时候分页查询最好在 SQL 层用TOP或ROW_NUMBER()限制返回行数而不是靠 ADO 游标硬扛。5. 本篇常见错排查RecordCount 为 -1 的排查按下面这个顺序走基本能定位到根因。错误一CursorLocation 写在 Open 之后。这是最高频的坑。rs.Open之后再设rs.CursorLocation不会报错但也不生效RecordCount 照样 -1。正确顺序永远是先设属性、再 Open。错误二用了 adOpenForwardOnly 却想要 RecordCount。只向前游标按设计就不维护行数这不是 bug。要计数就换adOpenStatic或adOpenKeyset。错误三提供程序不支持所选游标类型。某些 OLE DB 驱动比如部分 MySQL、Oracle 的旧版驱动不支持adOpenStatic你设了它也会被替换成最接近的类型结果 RecordCount 还是 -1。排查办法是打开后读一下rs.CursorType的实际值看是不是被改了。错误四LockType 和 CursorType 冲突导致游标被强制替换。比如adOpenStatic配adLockBatchOptimistic在某些提供程序上会触发游标降级。分页只读场景统一用adLockReadOnly最省事。错误五把 RecordCount 当空判断。判断记录集是否为空用rs.BOF And rs.EOF就够了不需要 RecordCount。这个习惯能帮你避开很多游标限制。提示如果你只是要判断有没有数据If rs.EOF Then比If rs.RecordCount 0 Then更快也更可靠后者在只向前游标下永远是 -1判断逻辑直接失效。排查时建议加一行调试输出把rs.CursorLocation、rs.CursorType、rs.RecordCount三个值一起打印出来对照本文第 3 节的表格一眼就能看出是哪个环节被替换了。6. 接入与验证用 TaoToken 快速验证模型侧逻辑游标配置调通之后如果你还想把数据查询逻辑接到大模型侧做进一步验证比如让模型帮你生成分页 SQL 或检查游标参数可以用 TaoToken 的模型对话能力快速试。它支持在浏览器里直接对话适合验证 SQL 生成、参数解释这类轻量任务。需要长期在编码工具里用的话可以看 Coding Plan把模型接入到日常开发流程里写 ADO 分页代码时让模型帮你补全游标参数。API 接入地址是 https://taotoken.net/api密钥在控制台创建具体参数参考接入文档。模型对话入口在 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentmodel_chatAPI Keys 管理在 https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentapi_keys。回到 ADO 本身最后再强调一个实用技巧分页场景下与其依赖AbsolutePage在客户端游标上跳页不如在 SQL 层用ROW_NUMBER()或LIMIT/OFFSET直接取当前页数据RecordCount 单独用一条COUNT(*)查。这样既避免了客户端游标的内存开销也不受提供程序游标支持的限制是数据量大时更稳的做法。
返回列表