根本原因是调用时用了局部变量(如declare定义的v_name),而mysql存储过程只识别用户变量(@var)或字面量;局部变量作用域限于当前过程,call时不可见,必须改用call proc(@name)或call proc('abc')。

调用时传了局部变量,但过程里收不到值
根本原因不是存储过程写错了,而是你用了局部变量(比如 DECLARE v_name VARCHAR(50))去调用过程,而 CALL proc(v_name) 中的 v_name 在会话层不可见。MySQL 存储过程只认用户变量(@var)或字面量。
- 检查调用语句:必须是
CALL my_proc(@name);或CALL my_proc('abc');,不能是CALL my_proc(local_var); - 如果前端用 C# / Java 传参,确认
SqlParameter的Value不是null——特别是整型参数设为0时,别写成new SqlParameter("p", null),要显式转成Convert.ToInt32(0) - 调试时在过程开头加
SELECT CONCAT('IN param: [', in_param, ']');,方括号能暴露前后空格或不可见字符
IN 参数在过程里查出来是 NULL,但明明传了值
常见错觉:你在过程里写了 SELECT @in_param;,结果是 NULL——这不是参数没传进来,而是你误查了同名用户变量,不是过程参数本身。
-
IN参数是只读副本,名字和用户变量重名也不会自动绑定;过程内直接引用in_param(无@)才是真值 - 别在过程里写
SET @in_param = 'xxx';,这只会污染用户变量,对IN参数毫无影响 - 字符串类参数要防隐藏字符:传入值带 BOM、零宽空格、全角空格时,
=判断会失败,改用TRIM(in_param) = '' OR in_param IS NULL
OUT 参数调用后取不到值,但过程里赋了值
OUT 参数的值只在存储过程执行完毕后才写回用户变量,过程内部查它永远是 NULL(除非你手动 SET out_param = xxx),这不是 bug,是设计行为。
- 调用必须用用户变量:
CALL my_proc(@result);,不能用字面量或局部变量 - 过程内务必显式赋值:
SET out_param = 123;,初始值恒为NULL,不赋值就永远是NULL - 取值必须在
CALL之后立即执行:SELECT @result;,不要跨语句或跨连接依赖 - 如果过程有多个
OUT参数,确保每个都赋了非NULL值,否则客户端可能因类型不一致报错
参数为空时逻辑崩溃,怎么安全兜底
MySQL 对 NULL 的比较是三值逻辑,WHERE col = @param 或 IF @param = 'x' 在 @param 为 NULL 时既不进 THEN 也不进 ELSE,容易静默跳过关键分支。
- 所有输入参数开头集中校验:
IF in_param IS NULL THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'in_param 不能为空'; END IF; - 字符串判空别只用
IS NULL,加TRIM(in_param) = ''防空白 - 需要默认值时,优先用
COALESCE(in_param, 'default')而不是IFNULL(),更符合 SQL 标准且支持多参数 - 避免在
WHERE中写col = COALESCE(@param, col)这种写法——它会让索引失效,改用WHERE (@param IS NULL) OR (col = @param)
真正麻烦的从来不是“怎么写”,而是“谁在什么时候、以什么形式把什么值塞进了参数”——尤其当调用链路过长(C# → ADO.NET → MySQL Server → 存储过程)时,NULL 和空字符串会在某一层悄悄变形,必须每一层都做显式检查和打印验证。











