1. ADOQuery1.Open 与 ExecSQL 到底差在哪:从一次数据访问链路说起
如果你在 Delphi 里写过数据库代码,大概率见过这两种写法:ADOQuery1.Open和ADOQuery1.ExecSQL。很多人凭直觉记成「查询用 Open,增删改用 ExecSQL」,但真到排查问题时,比如游标一直停在dsOpening、事务没提交、RowsAffected拿不到值,就会发现这个直觉不够用。这篇就聚焦 Delphi 中 ADOQuery1.Open 与 ExecSQL 的底层差异,把结果集返回、游标状态、事务与锁行为拆开讲,并结合 TaoToken 统一 Key/API 通道演示两种调用在真实数据访问链路里的表现。
先说结论性的判断:Open走的是OpenCursor路径,它会真正去Recordset.Open,把游标打开、把结果集挂到数据集上,让Fields、RecordCount、Eof这些成员可用;而ExecSQL走的是Command.Execute路径,它只关心受影响行数,不建立可浏览的游标。这个差异不是风格问题,而是 VCL 源码里两条完全不同的分支。
适合谁看?如果你正在用 Delphi 7 到 Delphi 11 之间的版本维护老系统,或者你在用 ADO 组件对接远程数据服务,又或者你通过 TaoToken 这类统一 API 通道把模型能力和数据访问串在一起,那这篇的配置片段和排障步骤可以直接拿去用。核心检索词就是 ADOQuery、Open、ExecSQL 三者的内部区别,以及它们在真实链路中的行为对照。
我试过在一个批量更新场景里把ExecSQL误写成Open,结果程序不报错,但RecordCount返回 -1,后续依赖行数的逻辑全部走偏。这类坑不靠猜,得看源码和实测。
2. TaoToken 前置准备:统一 Key 与 API 通道怎么配
在把 ADOQuery 的两种调用接进真实链路之前,先把 TaoToken 这一侧的通道准备好。TaoToken 提供统一的 Key 和 API 入口,官网是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 基址是 https://taotoken.net/api 。它的作用是让你不用为每个模型或服务单独维护一套鉴权和地址,用一个 Key 走统一通道。
你需要先拿到 API Key。进入控制台的 API Keys 页面创建,地址是 https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api_keys&utm_campaign=rewrite 。创建后复制那串以sk-开头的字符串,注意只显示一次,丢了就重新生成。这一步别截图发群里,Key 泄露等于别人能刷你的额度。
拿到 Key 之后,你要明确三件套:Base URL、Key、Model ID。Base URL 填https://taotoken.net/api,Key 填刚复制的那串,Model ID 按你实际要调用的模型填。这三件套在后面的配置片段里会反复出现,缺一个都会导致 401 或连接失败。
如果你用的是 Claude Code 这类编码工具,TaoToken 也提供了对应的接入方式,文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite 。Claude Code 的接入页在 https://taotoken.net/claude-code-anthropic?utm_source=taotoken_aicg_blog_end&utm_content=claudecode&utm_campaign=rewrite ,里面写了 Base URL 和 Key 怎么填。对于长期编码和 Agent 场景,可以考虑 Coding Plan,地址是 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding_plan&utm_campaign=rewrite ,适合需要持续调用的项目。
这里要强调一点:TaoToken 是统一 API 通道,不是让你绕过什么限制的工具,它的价值在于把多个模型的调用收敛到一个入口,减少你在 Key 管理和地址切换上的重复劳动。配置时把 Base URL 写全,不要漏掉/api这一段,否则请求会打到错误路径。
准备好这三件套后,我们回到 Delphi 侧,看 ADOQuery 的两种调用怎么和这条链路配合。
3. 可复制配置:ADOQuery 参数与 TaoToken 三件套片段
这一节给出可以直接复制的配置。先看 Delphi 侧 ADOQuery 的关键属性设置,再看 TaoToken 的三件套片段。两者配合的方式是:ADOQuery 负责本地或远程数据库的访问,TaoToken 负责模型/API 通道,你在同一个数据访问链路里可能既查库又调模型。
先看 ADOQuery 的配置。假设你要执行一条带参数的更新语句,用 ExecSQL:
procedure TForm1.RunExecSQL; begin ADOQuery1.Close; ADOQuery1.SQL.Clear; ADOQuery1.SQL.Add('UPDATE Orders SET Status = :Status WHERE OrderID = :OrderID'); ADOQuery1.Parameters.ParamByName('Status').Value := 'Paid'; ADOQuery1.Parameters.ParamByName('OrderID').Value := 1001; ADOQuery1.CommandTimeout := 30; ADOQuery1.ExecuteOptions := [eoExecuteNoRecords]; try ADOQuery1.ExecSQL; Memo1.Lines.Add('受影响行数: ' + IntToStr(ADOQuery1.RowsAffected)); except on E: Exception do Memo1.Lines.Add('ExecSQL 失败: ' + E.Message); end; end;再看查询场景,用 Open:
procedure TForm1.RunOpen; begin ADOQuery1.Close; ADOQuery1.SQL.Clear; ADOQuery1.SQL.Add('SELECT OrderID, Status, Amount FROM Orders WHERE Status = :Status'); ADOQuery1.Parameters.ParamByName('Status').Value := 'Paid'; ADOQuery1.CursorType := ctStatic; ADOQuery1.LockType := ltReadOnly; ADOQuery1.CursorLocation := clUseClient; try ADOQuery1.Open; while not ADOQuery1.Eof do begin Memo1.Lines.Add(ADOQuery1.FieldByName('OrderID').AsString); ADOQuery1.Next; end; except on E: Exception do Memo1.Lines.Add('Open 失败: ' + E.Message); end; end;注意CursorType和LockType的选择会直接影响锁行为。ctStatic加ltReadOnly是只读快照,适合报表;如果你用ctDynamic加ltOptimistic,游标会随数据变化,锁粒度也不同。CursorLocation设为clUseClient时结果集拉到客户端,clUseServer则留在服务端,后者对大数据量更友好但游标状态更敏感。
接下来是 TaoToken 的三件套片段。如果你用 JSON 配置,可以这样写:
{ "base_url": "https://taotoken.net/api", "api_key": "sk-你的Key", "model_id": "你的模型ID" }如果你用 TOML:
[taotoken] base_url = "https://taotoken.net/api" api_key = "sk-你的Key" model_id = "你的模型ID"如果你用 Claude Code 的 settings 风格:
{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_API_KEY": "sk-你的Key", "ANTHROPIC_MODEL": "你的模型ID" } }这三件套里的 Base URL、Key、Model ID 必须和你在控制台创建的一致。路径不要自己加斜杠或改大小写,https://taotoken.net/api就是完整基址。把这段配置和上面的 ADOQuery 代码放在同一个项目里,你就有了一个既能查库又能调模型的完整链路。
4. 验证请求与成功结果:Open 与 ExecSQL 的执行对照
配置好之后,怎么验证两种调用真的按预期工作?这一节给出可跟做的验证步骤和预期结果。
第一步,验证 ExecSQL 的受影响行数。执行上面RunExecSQL的代码,如果更新了 1 行,RowsAffected应该返回 1。这里的关键是ExecuteOptions里加了eoExecuteNoRecords,它告诉 ADO 不要返回结果集,只拿行数。如果你去掉这个选项,某些驱动会尝试返回一个空结果集,RowsAffected可能变成 -1。
第二步,验证 Open 的游标状态。执行RunOpen,在Open之后立刻检查ADOQuery1.State。正常应该是dsBrowse。如果你看到dsOpening一直不变,说明游标没打开成功,通常是连接或 SQL 有问题。RecordCount在clUseClient下能拿到准确值,在clUseServer下可能返回 -1,这是 ADO 的已知行为,不是 bug。
第三步,对照两者的资源释放。Open之后必须Close,否则游标一直占着连接。ExecSQL之后虽然不产生游标,但如果你复用了同一个 ADOQuery 去Open,也要先Close。实测下来,忘记Close会导致连接池耗尽,报「连接忙」或超时。
第四步,把 TaoToken 通道也验证一遍。用模型对话页面发一条测试请求,地址是 https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_content=models&utm_campaign=rewrite 。如果返回正常,说明 Key 和 Base URL 没问题。这一步和 ADOQuery 是独立的,但同属一个数据访问链路,建议一起测。
成功结果的判断标准:ExecSQL 返回正整数行数且无异常;Open 后State = dsBrowse、Eof可正常遍历;TaoToken 请求返回 200 且内容非空。三者都通过,说明链路通了。
这里给一个对照表,方便你快速比对:
| 维度 | Open | ExecSQL |
|---|---|---|
| 底层调用 | OpenCursor → Recordset.Open | Command.Execute |
| 结果集 | 有,可浏览 | 无 |
| 游标状态 | dsBrowse / dsOpening | 不涉及 |
| 返回值 | 无(靠数据集状态) | RowsAffected |
| 适用语句 | SELECT | INSERT/UPDATE/DELETE |
| 资源释放 | 必须 Close | 无需游标,但复用要 Close |
5. 常见报错排查:401、local proxy failed、reading choices、OAuth
这一节按真实报错来排。你在把 ADOQuery 和 TaoToken 串起来时,最可能撞上下面几类错误。
第一类,401 Unauthorized。这几乎都是 Key 的问题。检查三件套里的 Key 是否完整、有没有多余空格、是不是复制时漏了字符。如果你用的是 Claude Code 接入,确认ANTHROPIC_API_KEY填的是 TaoToken 的 Key,而不是别处的。401 不会因为 SQL 写错而出现,所以看到 401 先查鉴权,别去改 SQL。
第二类,local proxy failed。这个报错通常出现在你本地配了转发但目标地址不通的时候。检查 Base URL 是不是写成了https://taotoken.net/api,有没有多写端口或路径。如果你在 settings 里同时配了多个环境变量,确认没有互相覆盖。这个错误和 ADOQuery 无关,是通道侧的问题。
第三类,reading choices 相关报错。这类错误一般出现在解析返回结构时,比如你期望拿到choices字段但返回体结构不对。检查 Model ID 是否填错,不同模型的返回格式可能有差异。如果你在代码里硬编码了字段路径,换成实际返回的结构再试。
第四类,OAuth 相关报错。如果你用的是需要 OAuth 的接入方式,确认 token 没过期。TaoToken 的 API Key 方式不涉及 OAuth 流程,但如果你混用了其他鉴权方式,可能触发这类错误。统一用 API Key 最省事。
第五类,ADOQuery 侧的报错。Open报「未指定结果集」通常是 SQL 不是 SELECT;ExecSQL报「参数未赋值」是Parameters没填全。这两类错误和通道无关,看异常消息就能定位。
排障顺序建议:先确认 TaoToken 通道能通(用模型对话页测),再确认 ADOQuery 单独能跑,最后才看两者配合。这样能把问题范围缩小到一半。
如果你在排障时需要对照接入文档,地址是 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite 。API Keys 管理在 https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api_keys&utm_campaign=rewrite 。这两个页面能覆盖大部分配置问题。
6. 把两种调用用对:接入文档与 API Keys 的落地建议
回到最开始的问题:ADOQuery1.Open 和 ExecSQL 的内部区别,本质是「要不要结果集」和「要不要游标」的区别。Open 走 OpenCursor,建立可浏览游标,适合查询;ExecSQL 走 Command.Execute,只拿行数,适合增删改。理解这一点,你就能在写代码时不再靠猜。
在 TaoToken 场景下,这条数据访问链路的价值在于统一。你用一套 Key 和 Base URL 就能对接模型能力,同时本地 ADOQuery 继续管数据库访问,两者不冲突。配置时把三件套写全,Base URL 用https://taotoken.net/api,Key 从控制台拿,Model ID 按实际填。
落地建议有三条。第一,ExecSQL 之后如果要复用 ADOQuery 去 Open,先 Close,避免游标冲突。第二,Open 的场景尽量明确 CursorType 和 LockType,别用默认值碰运气。第三,TaoToken 的 Key 定期轮换,控制台可以重新生成,旧 Key 失效后记得更新配置。
如果你需要长期在编码和 Agent 场景里调用,Coding Plan 的入口在 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding_plan&utm_campaign=rewrite 。接入文档和 API Keys 页面建议收藏,排障时直接翻。最后一步,把上面的RunExecSQL和RunOpen跑一遍,对照第 4 节的验证标准,确认你的链路是通的。