MySQL数据库基本概念详解:参数传递、流程控制与业务逻辑封装

mysql存储过程是业务逻辑下沉的关键,需严守参数规则与异常处理:in参数修改不影响调用方;out/inout必须用@变量接收且inout需预初始化;if/case须配declare exit handler,推荐resignal或signal抛错。

MySQL数据库基本概念详解:参数传递、流程控制与业务逻辑封装

MySQL 存储过程不是“可有可无”的语法糖,而是业务逻辑下沉到数据库层的关键手段——但必须写对参数类型、流程分支和错误处理,否则反而埋下隐性故障。

IN/OUT/INOUT 参数到底怎么用才不踩坑

很多人以为 IN 就是“传进去”,OUT 就是“拿出来”,但实际调用时容易漏掉关键细节:

  • IN 参数在存储过程中被修改,不会影响调用方的原始变量(比如传入 @x := 10,过程里改 SET p_in := 20,调用后 @x 还是 10);
  • OUT 参数必须用用户变量接收,且调用前无需赋值(CALL proc8(1001, @name); SELECT @name;),否则返回 NULL
  • INOUT 是两者的混合,调用前要初始化,过程内可读可写,调用后能拿到新值;
  • 所有 OUTINOUT 参数,都必须在 CALL 时传入**用户变量**(以 @ 开头),不能传字面量或字段名。

IF / CASE 流程控制必须配异常处理器

只写 IF ... THEN ... ELSE 而不加异常捕获,等于裸奔——尤其涉及事务时,出错就卡在中间状态:

  • MySQL 的 DECLARE EXIT HANDLER FOR SQLEXCEPTION 不是可选项,是强需求;
  • 别用 ROLLBACK 后直接 SELECT 'error',这会让应用层收不到标准错误码;推荐用 RESIGNAL(保留原错误信息)或 SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'xxx'
  • CASE 适合多分支等值判断(如状态码映射),IF 更适合布尔逻辑(如 IF v_balance );
  • 注意 IF 必须成对出现:IF ... THEN ... END IF;,漏掉 END IF 会报语法错误,且错误提示常指向末尾而非真实缺位处。

局部变量声明位置和作用域极易混淆

MySQL 要求所有 DECLARE 必须放在 BEGIN 后的最前面,任何 SQL 语句之前——顺序错就报错:

  • 局部变量(DECLARE v_count INT DEFAULT 0;)只在当前 BEGIN...END 块内有效,嵌套块中需重新声明;
  • 别和用户变量(@v_count)混用:后者跨语句存活,但不可用于 INTO 子句的目标(SELECT x INTO v_local 合法,SELECT x INTO @v_user 报错);
  • 想把查询结果存进局部变量,必须用 SELECT ... INTO v_var,不能用 SET v_var = (SELECT ...)(子查询返回多行会报错,而 INTO 会明确报 Subquery returns more than 1 row)。

真正难的不是写出一个能跑的存储过程,而是让它在并发转账、批量导入、定时对账等真实场景下不丢数据、不错账、不锁死。参数类型选错、异常没兜底、变量作用域误判——这些地方出问题,日志里往往只有一行 ERROR 1305 (42000): PROCEDURE xxx does not exist,其实根本不是不存在,是上次创建因语法错误静默失败了。