存储过程就是数据库里的“预编译函数”
它不是视图,也不是普通 SQL;而是一段写死在 MySQL 服务器上的、带名字的 SQL 逻辑块,创建时就完成语法检查和执行计划优化,后续调用直接走二进制路径。你可以把它理解成数据库原生支持的、能存参数、能写 if/while、能返回结果集或输出值的“本地方法”——
CALL proc_name()就是它的调用方式。
为什么非得改 DELIMITER
才能创建?
MySQL 默认把分号
;当作语句结束符,但存储过程中大量使用
;(比如
SELECT ...;、
SET @x = 1;),不改分隔符会导致客户端提前提交、解析失败,报错类似
ERROR 1064 (42000)。 必须先执行
DELIMITER //(或
$、
$$等非分号符号)
CREATE PROCEDURE体内部所有语句仍用
;,只有结尾的
END //才触发真正执行 建完务必还原:
DELIMITER ;,否则后续普通 SQL 会卡住
IN
/OUT
/INOUT
参数到底怎么用?
这不是可有可无的修饰词,而是决定数据流向的关键标记。没声明模式的参数默认是
IN,只进不出;想从过程里拿回值,必须显式声明
OUT或
INOUT,且调用时必须传用户变量(以
@开头)。
IN:传入值,过程内可读可改,但改了不影响外部变量
OUT:不关心传入值,过程内赋值后,调用方通过同名
@var读取结果
INOUT:先传值进去,过程里可读可改,结束后外部
@var被覆盖为新值 错误示范:
CALL proc(@x);中
@x未初始化 →
OUT参数会得到
NULL,不是报错
删不了、改不了、查不到?这些操作陷阱最常被忽略
MySQL 不支持
ALTER PROCEDURE,也没有“编辑保存”式热更新;所谓“修改”,本质是
DROP+
CREATE两步。而查看定义必须用
SHOW CREATE PROCEDURE proc_name,
SELECT * FROM information_schema.routines只返回元信息,
routine_definition字段在 MySQL 8.0+ 才默认可见(低版本可能为空)。 删除前加
IF EXISTS:避免不存在时报错中断脚本 ——
DROP PROCEDURE IF EXISTS proc_name别依赖 Workbench 的“修改”按钮:它底层仍是 drop+create,若过程正在被业务调用,中间存在空窗期 跨库查存储过程?
routine_schema字段必须匹配目标库名,大小写敏感(尤其在 Linux 部署环境)
真正难的从来不是写出来,而是当一个 300 行的存储过程在生产库跑着,你发现某处
WHERE条件漏了索引字段,又不敢直接
DROP——这时候没有调试器、没有日志输出、没有事务回滚点,只有
SELECT+
ROLLBACK+ 深呼吸。
