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

资讯详情

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

SQLDMO 还原 Northwind 得先杀连接进程?TaoToken 供 Key 让 Codex 对照 EnumProcesses

SQLDMO 还原 Northwind 得先杀连接进程?TaoToken 供 Key 让 Codex 对照 EnumProcesses 在 C# WinForms 里用 SQLDMO 还原 Northwind最容易卡住的往往不是备份而是还原Common.ShowMsg只弹一句「数据还原失败」你根本看不出到底是 Northwind 还有连接占用、D:/NorthwindBak这个备份路径写错还是 sa 登录本身没过。本文按排障视角把还原前那段EnumProcessesKillProcess的逻辑拆开逐条对照。模型通道这边先在 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 注册 TaoToken 并创建 Key再把 Codex 的 Base URL 填成https://taotoken.net/api不带/v1也不要填官网地址让 Codex 帮你核对列名判断、SPID/DBNAME 取值和ReplaceDatabase的先后顺序。TaoToken 在这里只提供 Key 和 Base URLStep里的pBar1进度、KillProcess、Connect这些动作仍然在你本机执行。一、还原 Northwind 只抛 Common.ShowMsg先分清是哪一类失败原文的实现分成两个按钮备份侧用的是SQLDMO.BackupClassSQLDMO.SQLServerClass。先LoginSecure false再Connect(Common.MySettings.SqlServerName, sa, )然后设置Action为备份数据库、Database为 Northwind、Files指向D:/NorthwindBak、BackupSetName和BackupSetDescription写清楚、Initialize true把PercentComplete事件挂到Step上刷新pBar1最后SQLBackup(oSQLServer)。异常统一被catch住丢给Common.ShowMsgfinally里DisConnect()。还原侧是SQLDMO.RestoreClass关键差别在于SQLRestore之前多了一段进程清理先Connect再EnumProcesses(-1)拿回一个QueryResults在前几列里找列名叫SPID和DBNAME的位置然后逐行取值只要DBNAME等于 Northwind 就KillProcess(lPID)。清完之后才设置Action、Database、Files、FileNumber 1、ReplaceDatabase true再执行SQLRestore。这套写法的意图很明确ReplaceDatabase true表示允许覆盖同名库但它并不能把已有连接踢掉。只要还原目标 Northwind 上还挂着别的会话比如你刚打开 SSMS 查过表、或者程序里另一个连接池没释放SQLRestore就会失败。而失败信息只经过Common.ShowMsg抛出弹出的是一整段ex.ToString()里面既有可能是「因为数据库正在使用所以无法获得对数据库的独占访问权」也可能是「无法打开备份设备」或者「用户 sa 登录失败」。三种原因的堆栈长度差不多肉眼扫一眼很难立刻定位这就是本篇要解决的问题。按经验还原失败先归三类连接占用类Northwind 上还有活动会话EnumProcesses没清干净或者根本没走清理逻辑。路径与设备类oRestore.Files给的不是有效备份设备。SQLDMO 的Files要指向磁盘上的备份文件本身而不是目录名。登录与权限类sa密码为空、SQL Server 未启用混合验证、或者连接串里的实例名写错。还有一类容易被忽略的运行时问题SQLDMO 是 32 位 COM 组件项目平台目标设成 x64 时new SQLDMO.SQLServerClass()会直接抛80040154。二、TaoToken 前置Key、Base URL 该填在哪这一步只做两件事拿 Key把 Codex 的出口指过去。打开 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 完成注册进入控制台创建 API Key。Key 在创建后只完整显示一次复制下来先存到本地密码管理器或者临时文本里。这个 Key 就是后面YOUR_API_KEY的位置。然后用这个地址作为 Codex 的 Base URLhttps://taotoken.net/api注意三个细节不带结尾斜杠不带/v1也不是官网首页地址。很多人习惯性把https://taotoken.net直接粘进base_url结果请求打到站点首页返回 HTML报错看起来像 JSON 解析失败其实方向一开始就错了。整篇文章里 TaoToken 的角色就是提供 Key 和 Base URL 这两样东西数据库那边该用什么账号、该杀哪个 SPID全部由你在本机判断和执行。三、可复制配置~/.codex/config.toml 与环境变量Codex 的配置文件放在用户目录下的.codex/config.toml。Windows 是C:\Users\你的用户名\.codex\config.tomlmacOS 和 Linux 是~/.codex/config.toml。文件不存在就新建。model MODEL_ID model_provider taotoken [model_providers.taotoken] name TaoToken base_url https://taotoken.net/api env_key TAOTOKEN_API_KEY wire_api chatMODEL_ID换成你在控制台里确认可用的模型标识。wire_api先按chat写走的是常见的对话补全协议如果你的模型通道确认支持 responses 协议再改成responses试一次不要一上来就两个都写。接着把 Key 放进环境变量配置里只引用变量名不把明文写进 tomlmacOS / Linuxexport TAOTOKEN_API_KEYYOUR_API_KEYWindows PowerShell$env:TAOTOKEN_API_KEYYOUR_API_KEY想把变量固化到当前用户Windows 用setx TAOTOKEN_API_KEY YOUR_API_KEY设置完重开一个终端不然旧进程读不到。四、让 Codex 对照 EnumProcesses 与 KillProcess 的提问法配置就绪后不要直接把整段还原代码丢过去问「为什么报错」那样回答会很泛。把范围收紧到进程清理这一段按下面的顺序喂给它。先贴一段改写后的清理逻辑变量名和原版不同但语义一致private void KillNorthwindSessions(SQLDMO.SQLServer srv) { SQLDMO.QueryResults rows srv.EnumProcesses(-1); int pidCol -1, dbCol -1; for (int c 1; c rows.Columns; c) { string col rows.get_ColumnName(c).Trim().ToUpperInvariant(); if (col SPID) pidCol c; else if (col DBNAME) dbCol c; } if (pidCol 1 || dbCol 1) throw new InvalidOperationException(EnumProcesses 缺少 SPID/DBNAME 列); for (int r 1; r rows.Rows; r) { string db rows.GetColumnString(r, dbCol); if (string.Equals(db, Northwind, StringComparison.OrdinalIgnoreCase)) srv.KillProcess((int)rows.GetColumnLong(r, pidCol)); } }然后在 Codex 里用这样的提示词这是 C# WinForms 里 SQLDMO 还原 Northwind 前的进程清理逻辑。 背景oRestore.ReplaceDatabase true但还原仍报「数据库正在使用」。 请逐条检查 1. get_ColumnName 返回的列名是否可能不是 SPID/DBNAMEToUpperInvariant 后是否需要处理空格或下划线 2. GetColumnLong 与 GetColumnString 的行列索引是否都从 1 开始 3. KillProcess 会不会把当前连接自己的 SPID 也杀掉 4. 清理动作必须在 SQLRestore 之前完成这个顺序在代码里是否有保证。 只针对这四点给出结论和修改建议不要重写整个还原流程。这样问的好处是Codex 会聚焦在你给出的四个假设上而不是泛泛地讲一遍 SQLDMO 用法。尤其第 2 点和第 4 点是这类代码在实际排障里最常踩的QueryResults的行列索引从 1 开始写成 0 会直接越界而清理和还原之间如果插了别的耗时操作新的连接又可能建回来。五、验证请求与成功结果配置改完先验证通道再验证数据库逻辑顺序别反。第一步命令行确认 Key 和 Base URL 能通curl https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d {model:MODEL_ID,messages:[{role:user,content:reply ok}]}成功时返回的是标准 JSONchoices数组里有内容HTTP 状态码 200。如果返回 401先检查环境变量有没有生效返回 404检查base_url是不是被误加了路径。第二步在项目目录里启动 Codex把上面那段提示词发进去。判断成功的标准是它明确指出GetColumnLong/GetColumnString的索引基准并且确认KillProcess需要在SQLRestore之前。如果它开始复述整份还原代码说明提示词范围太宽按第四节的模板重发一次。第三步回到程序本身验证。把平台目标改成 x86重新生成打开 SSMS 故意在 Northwind 上留一个查询窗口不关再点还原按钮。这时预期结果是进度条pBar1从备份完成事件推进到 100%不再弹出Common.ShowMsg的失败提示Northwind 的数据回到备份时点。六、本篇常见错排查Base URL 写错。https://taotoken.net/api/、https://taotoken.net/api/v1、https://taotoken.net都是错的只有https://taotoken.net/api是正解。Key 没进环境变量。改完系统变量没重开终端或者config.toml里env_key写的名字和实际变量名大小写不一致。EnumProcesses 列名匹配不到。不同 SQL Server 版本返回的列名大小写、是否有前导空格并不完全一致。判断前统一Trim()再ToUpperInvariant()比只调ToUpper()稳。索引从 0 开始取值。QueryResults的行和列都从 1 开始GetColumnString(0, dbCol)会抛异常被catch包住后又是一句笼统的失败提示。KillProcess 杀到自己。如果连接串里把默认库设成了 Northwind那么当前会话本身就在目标库里清理时会把自己也杀掉后面的SQLRestore必然失败。清理用的连接保持在 master 上。Files 指向目录而不是备份文件。备份时oBackup.Files指向D:/NorthwindBak是设备路径写法还原时oRestore.Files必须指向真实存在的备份文件FileNumber 1表示取第一个备份集文件不存在时报的是设备相关错误不是占用错误。SQLDMO 在 x64 下创建失败。把项目平台目标改为 x86或者换成 SMO 重写这一段。SQL Server 2008 R2 之后系统不再自带 SQLDMO需要额外安装向后兼容组件这也是「昨天还能跑今天就不行」的常见原因。sa 登录失败。oSQLServer.Connect(..., sa, )里密码为空要和服务端实际配置一致同时确认实例启用了混合验证模式。排障时把这几条按顺序过一遍基本能把「数据还原失败」这句笼统提示收敛到具体一行代码或一个配置项上。七、后续接入与排障资料如果你正在做这类老项目迁移或者本地环境排障Key 和 Base URL 的管理建议固定下来Key 统一在控制台的 API Keys 页面创建和吊销地址是 https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentapi-keys Codex 的config.toml、环境变量写法、协议选择这些细节对照接入文档 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentdoc 逐项核对比自己试错快很多。需要长期在本地跑 Codex 做编码和排障的可以走 Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentcoding-plan 把 Key 和通道固定成一套配置后面再遇到 SQLDMO 这类旧组件问题直接按第四节的提问模板复用即可。
返回列表