SQL 存储过程与函数实战

1次阅读

该选存储过程还是函数取决于调用场景:多步操作(如更新订单、扣库存)用存储过程,单值计算(如算总金额)用函数;mysql函数禁止insert/update/delete且不可改表,而存储过程可执行dml但不能在select中直接调用。

SQL 存储过程与函数实战

存储过程和函数到底该选哪个

看调用场景:需要执行多步操作(比如更新订单、扣库存、发通知)就用 存储过程;只想要一个计算结果(比如根据订单ID算总金额)就用 函数。MySQL 里函数不能有 INSERT/UPDATE/DELETE,否则直接报错 Error 1418;而存储过程可以,但不能在 SELECT 语句里直接调用。

MySQL 函数里改不了表,但又真得写点逻辑怎么办

常见错误是把业务校验逻辑硬塞进函数,比如“检查用户余额是否足够”,结果发现没法查表或更新状态,只能干瞪眼。这时候要么拆出去——把校验放到应用层或存储过程中做;要么换思路:用 SELECT ... INTO 把查询结果赋给变量,在存储过程里判断后走不同分支。

  • 函数里只允许 SELECT 查询(且必须有 INTO 或返回值),不能带事务控制
  • DETERMINISTICNO SQLREADS SQL DATA 这三个特性声明不是可选的——不加可能被 MySQL 拒绝创建
  • 函数在 WHERE 子句中频繁调用时,性能容易崩,尤其涉及子查询或大表 JOIN

存储过程调试难?先关掉那个自动提交

很多人写完 CALL my_proc() 发现数据没变,其实是被自动回滚了——因为默认开启 AUTOCOMMIT=1,而存储过程里没显式 START TRANSACTIONCOMMIT,每条语句单独提交,中间出错就卡住不动。更糟的是,有些 ide(比如早期版本的 DBeaver)会静默吞掉存储过程里的 SELECT 结果集,让你以为没输出。

  • 调试前先执行 SET AUTOCOMMIT = 0,再手动 COMMITROLLBACK
  • SELECT 'step 1'; 在关键位置打点,确认流程走到哪了
  • 注意 OUT 参数必须在调用时用变量接收,比如 CALL calc_total(123, @result); SELECT @result;

postgresql 的函数和 MySQL 完全不是一回事

PostgreSQL 里 function 默认就是事务内可读写,还能指定语言(plpgsqlsql、甚至 python),而 MySQL 的函数是纯“表达式友好型”,连临时表都受限。最常踩的坑是:把 PostgreSQL 习惯带到 MySQL,写了个带 UPDATE 的函数,结果死活建不成功。

  • PostgreSQL 函数可以用 PERFORM 执行无返回 INSERT/UPDATE,MySQL 不行
  • PostgreSQL 支持 RETURN QUERY 直接返回结果集,MySQL 存储过程只能靠多个 SELECT 输出,客户端要能处理多结果集
  • MySQL 存储过程没有标准的异常捕获语法(如 BEGIN ... EXCEPTION),只能靠 DECLARE HANDLER,而且只对特定错误码有效

数据库迁移时,别光看语法像不像,重点盯住“能不能改数据”“有没有事务上下文”“返回值怎么拿”这三件事。细节差一点,运行时才暴露,比编译报错更难查。

text=ZqhQzanResources