mysql游标必须在存储过程内按顺序声明:先变量、再游标、后错误处理器,且仅限存储过程或函数中使用;open前未正确定义游标或顺序错乱将直接导致语法错误。

游标声明位置错误导致语法解析失败
MySQL要求游标必须在变量声明之后、OPEN之前声明,且所有DECLARE语句必须集中放在存储过程开头。如果把DECLARE cursor_name CURSOR FOR ...写在OPEN之后或变量声明中间,会直接报错“Cursor declaration after handler declaration”或类似语法错误,根本不会执行到读取阶段。
- 正确顺序:先
DECLARE变量 → 再DECLARE游标 → 然后DECLARE CONTINUE HANDLER→ 最后OPEN - 常见误写:在
OPEN cur后补加游标声明,或把游标和SET混在一起 - Navicat等工具里直接建游标(不包在
CREATE PROCEDURE内)也会报错,游标只能存在于存储过程/函数作用域中
查询语句本身无结果但未暴露问题
游标底层执行的是SELECT语句,如果该语句返回空集,OPEN能成功,但第一次FETCH就触发NOT FOUND,done被设为1,循环直接跳过——看起来像“读不到数据”,其实是查不到数据。
- 用相同
SELECT语句在命令行单独执行,确认是否真有数据 - 注意表名、字段名大小写(Linux下敏感)、别名缺失(如
UNION多子查询时没给统一别名会导致字段映射失败) - 避免隐式类型转换干扰:比如
WHERE id = '123'查INT字段,可能因字符转数字失败而漏匹配
NOT FOUND 处理器被其他 SELECT 干扰
CONTINUE HANDLER FOR NOT FOUND是作用于整个存储过程块的,不是仅绑定游标。只要任意SELECT ... INTO没查到数据,就会触发同一个处理器,把你的游标结束标志done设成1,导致游标还没开始读就退出。
- 必须为游标专用的
done变量,并在每次非游标查询后立刻SET done = 0 - 不要复用同一变量接收多个
SELECT INTO结果,否则残留值+NOT FOUND副作用叠加 - 示例:游标FETCH后做子查询更新,子查询没命中 →
done变1 → 下轮FETCH前判断直接跳出
大文本字段引发 Packet too large 或 OOM 中断
当游标查询包含TEXT、MEDIUMTEXT等大字段时,MySQL会尝试将整行加载进内存。若单行超max_allowed_packet限制,OPEN直接报错“Packet too large”;若内存不足,则连接中断或进程被OOM Killer杀掉,表现为“无声失败”。
- 检查
SHOW VARIABLES LIKE 'max_allowed_packet';,确保≥单行最大文本长度+其他字段开销 - 临时调大:
SET SESSION max_allowed_packet = 512 * 1024 * 1024; - 更稳妥做法:游标查询只选必要字段,用
id代替全文本,后续用UPDATE或应用层分批拉取内容
游标读不到数据,十有八九不是逻辑写错了,而是声明顺序、查询实际结果、处理器作用域或资源限制这四个点中的某一个卡住了——先看错误日志有没有Packet too large或语法提示,再拿SELECT语句单独跑一遍,最后检查done变量有没有被无关查询偷偷改掉。











