mysql 8.0+升级后存储过程卡住主因是drop/create被正在执行的旧过程阻塞,需查events_statements_current定位线程并kill;保留字如rank、json等须加反引号或改名,可用information_schema.keywords批量检测风险。

MySQL 8.0+ 升级后存储过程编译卡住或无响应
不是语法写错了,大概率是 DROP/CREATE 过程时被阻塞——旧过程正在被应用调用,但连接没释放,导致 DROP PROCEDURE IF EXISTS 一直等待锁。Workbench 没反应、命令行 Ctrl+C 才退出,就是典型表现。
查 performance_schema.events_statements_current 找正在执行该过程的 SQL:
SELECT THREAD_ID, SQL_TEXT FROM performance_schema.events_statements_current WHERE SQL_TEXT LIKE '%proc_name%';
再通过 THREAD_ID 关联 performance_schema.threads 获取 PROCESSLIST_ID,最后用 KILL <id></id> 干掉占用连接。别急着改存储过程代码,先清现场。
存储过程中裸写 rank、json、group 等字段名直接报错
升级后建表可能不报错,但存储过程里引用这些字段时会炸:错误信息 ERROR 1064 near 'rank' 就是明确提示——rank 被当关键字解析了,不是你漏写了逗号。
- 必须在所有出现位置加反引号:
`rank`,包括DECLARE变量、SELECT列、UPDATE赋值、INSERT INTO ... VALUES的字段列表 -
SET sql_mode = 'ANSI_QUOTES'不起作用:它只让双引号能当标识符用,不影响保留字限制;且 DDL(如CREATE PROCEDURE)里"rank"依然非法 - ORM 或拼接 SQL 的地方容易漏:比如 Java 里用
String.format("SELECT %s FROM t", field),若field是"rank"就得提前处理成"`rank`"
如何批量发现存储过程里的保留字风险
别靠人眼扫,MySQL 自带 INFORMATION_SCHEMA.KEYWORDS 就是权威来源。执行:
SELECT WORD FROM INFORMATION_SCHEMA.KEYWORDS WHERE RESERVED = 1 AND WORD IN ('rank', 'json', 'window', 'recursive', 'role');
拿到当前版本的强制保留字列表后,导出所有过程定义:
SELECT ROUTINE_NAME, ROUTINE_DEFINITION FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_SCHEMA = 'your_db';
然后 grep 或正则匹配裸词(注意排除已加反引号的):rank(?!\`)、\bjson\b(?!\`)。重点盯视图、触发器、函数里那些不常维护的逻辑——它们不会出现在 SHOW CREATE TABLE 里,却最容易爆。
改名比加反引号更稳妥,但得改全链路
如果字段叫 order,优先改成 order_id 或 sort_order。好处不只是避开保留字,还能避免 ORM 映射歧义、JSON 序列化冲突、API 字段命名混乱。
但改名是脏活:除了改表结构,还得同步改所有存储过程里的引用、应用层 SQL 拼接、JDBC Resultset 取值、MyBatis resultMap、甚至前端模板里的字段名。漏一处,运行时报 Unknown column 'order' in 'field list'。
真正麻烦的是历史过程里嵌套调用——比如 proc_a 调 proc_b,而 proc_b 返回结果集含 rank 字段,proc_a 用 SELECT rank INTO @v FROM ... 就得全改。这种依赖链得画出来再动。











