MySQL存储过程无内置调试器,官方8.0.31起仅在MySQL Shell中提供实验性C++插件级debug命令,不支持存储过程;真实开发依赖SELECT日志或mysqlsh debugSession调试,但均有局限。

MySQL存储过程没有内置调试器,别指望 DELIMITER 加 SELECT 就能真断点
MySQL官方直到 8.0.31 才在 MySQL Shell 里加了实验性的 debug 命令,但仅支持 C++ 插件级调试,对存储过程无效。你写的 CREATE PROCEDURE 一旦出错,SHOW WARNINGS 只给一行 ERROR 1320 (45000): No RETURN found 这类泛泛提示,根本定位不到哪行变量没赋值、哪条 IF 判错了。
真实开发中,靠 SELECT CONCAT('debug: ', @var) 打日志不仅污染逻辑,还会因事务隔离或错误提前退出导致日志不全。更麻烦的是:存储过程里不能用 PREPARE 动态执行含 SELECT 的调试语句——MySQL 会报 ERROR 1295 (HY000): This command is not supported in the prepared statement protocol yet。
用 mysqlsh + util.debugSession() 是目前唯一接近“可视化断点”的方案
MySQL Shell(mysqlsh)从 8.0.27 起支持连接到正在运行的会话并注入调试钩子,虽不是图形界面,但能停在指定行、查变量、单步执行。前提是你的 MySQL 实例开启了 performance_schema 且用户有 SELECT 权限在 performance_schema 库下。
- 启动 mysqlsh 后先连上目标实例:
mysqlsh --uri user@host:port - 创建调试会话:
util.debugSession({host: "localhost", port: 3306, user: "dev", password: "xxx"}) - 在存储过程中想断点的位置插入:
SELECT SLEEP(0.001);(这是唯一被识别为“可中断点”的语句) - 执行过程后,在 mysqlsh 中输入
debugger.stepInto()即可停住,再用debugger.getLocals()查当前所有用户变量和参数值
注意:这个流程不支持游标遍历中的断点,FETCH 后的变量值不会实时更新到 getLocals() 返回结果里——你得手动再查一次 SELECT @cur_var。
SELECT 日志法必须加事务控制,否则并发下日志会串行或丢失
如果团队还在用 MySQL 5.7 或没权限开 performance_schema,那就只能回归手工日志。但直接在过程里写一堆 INSERT INTO debug_log VALUES (NOW(), 'step1', @var) 很危险:存储过程默认在 AUTOCOMMIT=OFF 下运行,而 INSERT 会隐式开启新事务,导致主流程事务被意外提交或回滚。
- 统一用临时表记录:
CREATE TEMPORARY TABLE debug_log (ts DATETIME, step VARCHAR(50), val TEXT); - 每条日志前加
SET @debug_ts = NOW();,避免NOW()在不同语句间微秒级偏移 - 关键变量打印必须转义:
INSERT INTO debug_log VALUES (@debug_ts, 'before_calc', COALESCE(CONVERT(@x USING utf8mb4), 'NULL'));,否则@x为NULL会导致整条INSERT失败 - 调试完立刻删表:
DROP TEMPORARY TABLE debug_log;,不然下次调用会报Table 'debug_log' already exists
Navicat / DBeaver 的“调试”按钮本质是模拟,不等于真断点
Navicat 16+ 和 DBeaver 23.0+ 都有存储过程“调试”入口,点下去会弹窗让你填参数,然后显示“执行完成”。它底层只是把你的 CALL proc_name(...) 包进一个带 SELECT 输出的包装块里,并非接入 MySQL 内核调试通道。所以:
- 它永远无法告诉你第 17 行的
WHILE循环为什么没进——只会返回最终结果集或错误码 - 若过程里有
LEAVE提前退出,工具不会高亮那行,只显示“Procedure executed successfully” - 遇到
ERROR 1175 (HY000): You are using safe update mode这类客户端限制报错,工具常静默吞掉,你得翻日志文件才能看到
真正卡住的地方,往往在变量作用域和隐式类型转换上:比如 DECLARE x INT DEFAULT 'abc'; 不报错,但后续 SET x = x + 1; 会让 x 变成 0,这种细节没有任何可视化工具能预警。


















