mysql存储过程通过in、out、inout三类参数明确区分数据流向:in只输入,out只输出且须用@变量接收,inout双向传递且调用前必须初始化用户变量。

MySQL 存储过程怎么声明 IN/OUT 参数
MySQL 存储过程不支持“输入输出”混合参数(即类似 INOUT 那种单个参数既读又写),但可以用 IN、OUT、INOUT 三类明确区分——关键不是“能不能传”,而是你得用对类型,否则调用时变量值不会回写。
常见错误:把 OUT 参数当成函数返回值直接赋给变量,结果发现变量还是 NULL;或者在调用时没用用户变量(@var)接 OUT,导致值丢了。
-
IN:只进不出,过程内可读,调用者传值即可,不用预定义变量 -
OUT:只出不进,过程内必须赋值,调用时必须用用户变量(如@result)接收 -
INOUT:既进又出,调用前要初始化用户变量,过程内可读可改,返回新值
调用带 OUT 参数的存储过程为什么拿不到值
根本原因:MySQL 要求 OUT 和 INOUT 参数必须绑定到用户变量(以 @ 开头),不能是普通变量或字面量。直接写 CALL proc(123, @out) 是合法的,但 CALL proc(123, 'abc') 会报错 Incorrect argument type to a stored procedure。
典型错误现象:SELECT @out; 返回 NULL,即使过程里写了 SET out_param = 42; —— 这说明调用时没把 @out 作为参数传进去,或者过程体里漏了 SET。
- 调用前必须先声明用户变量:
SET @out_val = NULL; - 调用时参数位置严格对应声明顺序:
CALL get_user_count('admin', @out_val); - 过程内部必须显式赋值给
OUT参数名:SET out_param = (SELECT COUNT(*) FROM users WHERE role = in_role);
INOUT 参数的实际用法和陷阱
INOUT 看似方便,但容易误用成“传引用”的错觉。它只是把用户变量的当前值传入,过程内修改后,再把新值写回该变量——中间没有内存共享,也不影响其他同名变量。
性能上无额外开销,但逻辑复杂度上升:你得同时考虑初始值是否合理、是否需要判空、是否要保留原值做对比。多数场景其实用 IN + OUT 分开更清晰。
- 调用前必须初始化:
SET @counter = 5;,否则传入的是NULL - 过程内可读可写:
SET inout_param = inout_param * 2 + 1; - 调用后原变量被覆盖:
SELECT @counter;返回新值,不是原值加运算结果 - 不能用局部变量替代:
DECLARE tmp INT DEFAULT 10; CALL proc(tmp, @out);会报错,INOUT只认用户变量
一个能跑通的完整例子
别抄网上的残缺片段。下面这个过程接受用户名(IN),返回用户 ID(OUT),并把登录次数加 1(INOUT):
DELIMITER $$
CREATE PROCEDURE login_and_get_id(
IN user_name VARCHAR(50),
OUT user_id INT,
INOUT login_times INT
)
BEGIN
SELECT id INTO user_id FROM users WHERE name = user_name;
IF user_id IS NOT NULL THEN
UPDATE users SET login_count = login_count + 1 WHERE id = user_id;
SET login_times = login_times + 1;
END IF;
END$$
DELIMITER ;
调用方式:
SET @uid = NULL; SET @times = 3; CALL login_and_get_id('alice', @uid, @times); SELECT @uid, @times;
注意:如果表里没有 'alice',@uid 保持 NULL,@times 不变——因为 IF 块没执行,SET 没触发。这种边界逻辑,比语法本身更容易出问题。











