资讯详情

存储过程游标与条件处理程序:TaoToken 统一 Key 下的 MySQL 调试配置骨架

📅 2026/9/27 13:28:10 | 华诺云谱 👁 阅读
存储过程游标与条件处理程序:TaoToken 统一 Key 下的 MySQL 调试配置骨架
1. 游标死循环与 handler 不触发到底卡在哪存储过程里写游标遍历最让人抓头的不是语法不会写而是两种“看起来跑通了、其实埋着雷”的状态一种是WHILE TRUE DO ... END WHILE里FETCH拿不到数据却没人管循环一直转连接被拖死另一种是明明写了HANDLER报错却照样往外抛或者该退出的时候没退出CLOSE执行了两次。这篇聚焦的就是这个场景MySQL 存储过程中用 cursor 遍历结果集配合条件处理程序handler捕获SQLEXCEPTION和NOT FOUND把调试配置骨架搭起来。适合已经会写基础存储过程、但一遇到游标边界和 handler 触发时机就靠猜的同学。我会给出可复制的my.cnf与settings.json骨架演示怎么用 TaoToken 统一 Key 接入 AI 辅助工具来排查游标死循环和 handler 未触发最后用SHOW WARNINGS和日志把验证动作落地。先把结论摆前面游标本身不难难的是“循环什么时候该停”和“错误什么时候被谁接住”。这两件事一个靠NOT FOUND条件处理程序一个靠EXIT与CONTINUE的选择。配置骨架的作用是让你在调试阶段能看清 MySQL 到底抛了什么、handler 有没有被命中。2. TaoToken 前置统一 Key 与调试配置骨架在动手排查之前先把工具链理顺。我习惯用 TaoToken 的统一 Key 来接入 AI 辅助工具好处是模型对话、编码辅助、接口调试走同一个入口不用在多个平台之间来回切 Key。官网入口在 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 基址是 https://taotoken.net/api 注意 API 地址不带 UTM 参数。拿 Key 的路径很直接进控制台创建 API Key然后按需选择模型对话或 Coding Plan。如果你只是临时问几个游标报错的问题用模型对话就够如果是长期写存储过程、要接 Agent 做批量排查Coding Plan 更合适。下面给出一份settings.json骨架字段按你自己的工具实际支持情况调整核心是把 base_url 和 api_key 指向统一入口。{ provider: taotoken, base_url: https://taotoken.net/api, api_key: sk-你的统一Key, model: claude-sonnet, timeout_seconds: 60, retry: { max_attempts: 3, backoff_ms: 800 }, debug: { log_level: debug, log_sql_warnings: true } }这份配置里log_sql_warnings是我自己加的调试开关用来提醒自己在排查阶段把SHOW WARNINGS的输出一起带上。真正接入时模型对话入口在 https://taotoken.net/api?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 接入文档在 https://taotoken.net/api?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content Coding Plan 在 https://taotoken.net/api?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。把这几条记下来后面排障会反复用到。3. 可复制配置my.cnf 与存储过程骨架3.1 my.cnf 调试段MySQL 服务端的日志和错误输出是判断 handler 有没有被触发的第一手材料。下面这段my.cnf只加调试相关项生产环境记得把general_log关掉否则日志膨胀很快。[mysqld] log_error /var/log/mysql/error.log log_error_verbosity 3 general_log 1 general_log_file /var/log/mysql/general.log slow_query_log 1 slow_query_log_file /var/log/mysql/slow.log long_query_time 1 log_warnings 2log_error_verbosity 3会把 note 级别也写进错误日志游标遍历到末尾时的一些提示能看到。log_warnings 2让警告信息更完整配合SHOW WARNINGS使用。改完配置重启 MySQL或者用SET GLOBAL动态开一部分。3.2 游标 handler 骨架下面这个存储过程骨架把变量声明、游标声明、handler 声明、循环、关闭的顺序都摆正。顺序错了是新手最常见的坑变量必须在游标之前声明handler 必须在游标之后声明。DELIMITER $$ CREATE PROCEDURE p_cursor_demo(IN uage INT) BEGIN DECLARE done INT DEFAULT 0; DECLARE uname VARCHAR(100); DECLARE upro VARCHAR(100); DECLARE u_cursor CURSOR FOR SELECT name, profession FROM tb_user WHERE age uage; DECLARE CONTINUE HANDLER FOR NOT FOUND SET done 1; DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN GET DIAGNOSTICS CONDITION 1 err_sqlstate RETURNED_SQLSTATE, err_msg MESSAGE_TEXT; INSERT INTO proc_error_log(proc_name, sqlstate, err_msg, created_at) VALUES (p_cursor_demo, err_sqlstate, err_msg, NOW()); ROLLBACK; END; DROP TABLE IF EXISTS tb_user_pro; CREATE TABLE IF NOT EXISTS tb_user_pro( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(100), profession VARCHAR(100) ); OPEN u_cursor; read_loop: LOOP FETCH u_cursor INTO uname, upro; IF done 1 THEN LEAVE read_loop; END IF; INSERT INTO tb_user_pro VALUES(NULL, uname, upro); END LOOP; CLOSE u_cursor; END$$ DELIMITER ;这里有两个关键点。第一NOT FOUND用CONTINUE HANDLER把done置 1循环里靠IF done 1 THEN LEAVE主动退出而不是让FETCH报错去触发EXIT。第二SQLEXCEPTION用EXIT HANDLER捕获后写错误日志表再回滚。这样游标正常结束走LEAVE异常结束走 handler两条路分开不会互相干扰。3.3 错误日志表handler 里写日志需要一张表先建好CREATE TABLE IF NOT EXISTS proc_error_log( id INT PRIMARY KEY AUTO_INCREMENT, proc_name VARCHAR(64), sqlstate VARCHAR(10), err_msg VARCHAR(512), created_at DATETIME );4. 验证请求与成功结果4.1 调用与观察准备一点测试数据然后调用存储过程INSERT INTO tb_user(name, profession, age) VALUES (张三, 后端, 28), (李四, 前端, 35), (王五, 测试, 42); CALL p_cursor_demo(40); SELECT * FROM tb_user_pro;预期结果是tb_user_pro里只有张三和李四两行王五因为 age 42 大于 40 被过滤掉。如果这里出现死循环说明done没被正确置位或者LEAVE没写对。4.2 SHOW WARNINGS 验证调用完立刻执行SHOW WARNINGS;正常结束的情况下这里通常为空或者只有 note 级别信息。如果看到1329 No data - zero rows fetched说明NOT FOUND条件被触发了但你的 handler 可能没接住或者接住了却没退出循环。1329 是 MySQL 错误编号对应的标准 SQLSTATE 是02000这也是为什么捕获时要写NOT FOUND或SQLSTATE 02000而不是写 1329。4.3 日志验证去错误日志里搜存储过程名grep -i p_cursor_demo /var/log/mysql/error.log tail -n 50 /var/log/mysql/general.log如果 handler 被触发proc_error_log表里会有记录SELECT * FROM proc_error_log ORDER BY id DESC LIMIT 10;正常遍历结束时这张表应该是空的。如果里面有SQLEXCEPTION记录说明循环体里出了别的错比如插入字段类型不匹配。4.4 用 TaoToken 辅助排查把SHOW WARNINGS的输出、错误日志片段、存储过程定义一起丢给模型对话让它帮你判断是NOT FOUND没接住还是SQLEXCEPTION被误触发。模型对话入口在 https://taotoken.net/api?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。如果是长期做这类排查Coding Plan 在 https://taotoken.net/api?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 可以把排查脚本和配置一起管起来。5. 本篇常见错排查5.1 游标死循环症状是CALL之后一直不返回连接数上涨。原因通常是WHILE TRUE DO里没有退出条件或者done变量声明了但 handler 没写对。检查三处DECLARE CONTINUE HANDLER FOR NOT FOUND SET done 1;是否存在循环里IF done 1 THEN LEAVE read_loop; END IF;是否在FETCH之后LEAVE的标签名是否和LOOP前的标签一致。5.2 handler 未触发症状是报错照样抛到客户端proc_error_log里没记录。常见原因是 handler 声明顺序错了。MySQL 要求DECLARE HANDLER必须在所有DECLARE CURSOR之后否则报语法错或者行为不符合预期。另一个原因是条件写成了SQLSTATE 1329但 1329 是错误编号不是 SQLSTATE应该写NOT FOUND或SQLSTATE 02000。5.3 变量与游标顺序DECLARE uname VARCHAR(100);必须在DECLARE u_cursor CURSOR FOR ...之前。反过来写会直接报错。这个顺序在官方文档里有明确要求但很多人第一次写会忽略。5.4 CLOSE 执行两次如果EXIT HANDLER里写了CLOSE u_cursor而循环正常结束后又写了一次CLOSE在异常路径下可能重复关闭。解决办法是让NOT FOUND走CONTINUELEAVE正常路径关闭游标SQLEXCEPTION走EXIT在 handler 里关闭。两条路只关一次。5.5 参数与字段类型不匹配FETCH u_cursor INTO uname, upro;里变量类型要和SELECT出来的列类型兼容。VARCHAR(100)接TEXT可能截断接INT会隐式转换。排查时看SHOW WARNINGS有没有 truncation 警告。6. 把配置骨架用起来这套骨架的核心就三件事my.cnf打开日志、存储过程里把NOT FOUND和SQLEXCEPTION分开处理、用SHOW WARNINGS和错误日志表验证。TaoToken 统一 Key 在这里的角色是让你排查时能快速把日志和过程定义丢给模型对话不用在多个工具之间倒腾 Key。接入文档在 https://taotoken.net/api?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API Key 在 https://taotoken.net/api?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。最后留一个我踩过的坑general_log开着的时候存储过程里每一条INSERT都会写进 general log数据量大的时候日志涨得飞快。排查完记得关掉或者把general_log_file指到临时目录别让它把磁盘写满。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑