MySQL 8.0 存储过程必须显式声明IN/OUT/INOUT参数模式,否则报ERROR 1064;IN参数只读,OUT参数须用SELECT INTO或SET显式赋值且调用时必须用@用户变量接收,INOUT参数需调用前初始化并支持读写,DELIMITER须成对设置。

MySQL 8.0 存储过程必须显式声明 IN/OUT/INOUT 模式
不写模式关键字会直接报 ERROR 1064。哪怕只有一个输入参数,也得写成 IN user_id INT,不能简写为 user_id INT。
三种模式行为差异明显:
-
IN参数只读:过程内赋值(如SET user_id = 100)不影响调用者传入的值,也不影响后续逻辑——它只是个副本 -
OUT参数初始为NULL:必须在BEGIN...END内用SELECT ... INTO或SET显式赋值,否则调用后仍是NULL -
INOUT参数调用前需设初值(如SET @x = 5),过程内可读可写,返回的是修改后的值
调用带 OUT 或 INOUT 参数时必须用 @ 用户变量
这是最常踩的坑:输出参数不能是字面量、字段名或未定义标识符。
✅ 正确写法:
SET @result = 0; CALL calc_bonus(101, @result, @perf); SELECT @result;
❌ 错误写法:
-
CALL calc_bonus(101, 0, @perf);—— 字面量0无法接收输出 -
CALL calc_bonus(101, result, @perf);——result不是变量,会报Unknown column 'result' -
CALL calc_bonus(101, NULL, @perf);——NULL是值,不是变量,同样失败
@ 变量作用域仅限当前会话,断开连接即丢失;不同客户端连接之间不共享。
DELIMITER 必须成对切换,且不能遗漏恢复
MySQL 默认以分号 ; 结束语句,但存储过程体内部每条 SQL 都要加分号。不换结束符会导致语法解析失败。
✅ 正确顺序:
DELIMITER // CREATE PROCEDURE get_count(OUT total INT) BEGIN SELECT COUNT(*) INTO total FROM users WHERE active = 1; END // DELIMITER ;
⚠️ 常见错误:
- 写了
DELIMITER //,但结尾忘了DELIMITER ;,导致后续所有命令都被当做一个超长语句解析 - 误用
DELIMITER $$后,又用;结束CREATE PROCEDURE,结果过程体被截断
建议统一用 //,视觉上更易匹配起止标记。
给 OUT/INOUT 赋值必须用 SELECT ... INTO 或 SET
不能用等号直接接查询表达式,MySQL 不支持这种写法。
✅ 正确方式:
SELECT AVG(salary) INTO avg_sal FROM employees;SET out_param = 100 * in_param;
❌ 错误方式:
-
avg_sal = SELECT AVG(salary) FROM employees;—— 语法错误 -
SELECT AVG(salary) FROM employees;—— 没INTO,结果不会进变量,avg_sal保持NULL
如果 SELECT ... INTO 查询无匹配行,目标变量仍为 NULL,需自行判断是否加默认值或异常处理。


















