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

存储过程和函数到底该选哪个
看调用场景:需要执行多步操作(比如更新订单、扣库存、发通知)就用 存储过程;只想要一个计算结果(比如根据订单ID算总金额)就用 函数。MySQL 里函数不能有 INSERT/UPDATE/DELETE,否则直接报错 Error 1418;而存储过程可以,但不能在 SELECT 语句里直接调用。
MySQL 函数里改不了表,但又真得写点逻辑怎么办
常见错误是把业务校验逻辑硬塞进函数,比如“检查用户余额是否足够”,结果发现没法查表或更新状态,只能干瞪眼。这时候要么拆出去——把校验放到应用层或存储过程中做;要么换思路:用 SELECT ... INTO 把查询结果赋给变量,在存储过程里判断后走不同分支。
- 函数里只允许
SELECT查询(且必须有INTO或返回值),不能带事务控制 -
DETERMINISTIC、NO SQL、READS SQL DATA这三个特性声明不是可选的——不加可能被 MySQL 拒绝创建 - 函数在
WHERE子句中频繁调用时,性能容易崩,尤其涉及子查询或大表 JOIN
存储过程调试难?先关掉那个自动提交
很多人写完 CALL my_proc() 发现数据没变,其实是被自动回滚了——因为默认开启 AUTOCOMMIT=1,而存储过程里没显式 START TRANSACTION 和 COMMIT,每条语句单独提交,中间出错就卡住不动。更糟的是,有些 ide(比如早期版本的 DBeaver)会静默吞掉存储过程里的 SELECT 结果集,让你以为没输出。
- 调试前先执行
SET AUTOCOMMIT = 0,再手动COMMIT或ROLLBACK - 用
SELECT 'step 1';在关键位置打点,确认流程走到哪了 - 注意
OUT参数必须在调用时用变量接收,比如CALL calc_total(123, @result); SELECT @result;
postgresql 的函数和 MySQL 完全不是一回事
PostgreSQL 里 function 默认就是事务内可读写,还能指定语言(plpgsql、sql、甚至 python),而 MySQL 的函数是纯“表达式友好型”,连临时表都受限。最常踩的坑是:把 PostgreSQL 习惯带到 MySQL,写了个带 UPDATE 的函数,结果死活建不成功。
- PostgreSQL 函数可以用
PERFORM执行无返回 INSERT/UPDATE,MySQL 不行 - PostgreSQL 支持
RETURN QUERY直接返回结果集,MySQL 存储过程只能靠多个SELECT输出,客户端要能处理多结果集 - MySQL 存储过程没有标准的异常捕获语法(如
BEGIN ... EXCEPTION),只能靠DECLARE HANDLER,而且只对特定错误码有效
跨数据库迁移时,别光看语法像不像,重点盯住“能不能改数据”“有没有事务上下文”“返回值怎么拿”这三件事。细节差一点,运行时才暴露,比编译报错更难查。