mysql中函数与存储过程本质不同:函数必须返回单值、禁用dml和事务,适用于纯计算;存储过程可执行dml、支持事务和多结果集,适用于业务逻辑封装。

MySQL函数和存储过程根本不是同一类东西,不能互换使用——选错就卡在语法、调用或事务上。
函数必须返回值,且只能用 RETURN 返回单个值
函数定义时强制要求 RETURNS 子句,类型必须明确(比如 INT、VARCHAR(50)),函数体里必须有且仅有一个 RETURN 语句。它不能没有返回值,也不能返回多个值或结果集。
常见错误现象:ERROR 1369 (HY000): FUNCTION xxx does not have a RETURN statement 或 ERROR 1418 (HY000): This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA(后者常因没加特性声明)。
- 函数参数默认全是
IN类型,不支持OUT或INOUT - 函数体内禁止出现
INSERT、UPDATE、DELETE等修改数据的语句(MySQL 默认限制) - 函数可在
SELECT、WHERE、ORDER BY中直接调用,比如SELECT id, calc_score(score) FROM students - 若需返回表结构数据,得用「表值函数」(MySQL 不原生支持,需用视图或存储过程替代)
存储过程用 CALL 调用,可无返回值但能输出多个结果
存储过程不声明返回类型,也不写 RETURN;它靠 OUT 或 INOUT 参数传出值,或直接用 SELECT 输出结果集。一个存储过程可以返回 0 个、1 个或多个结果集,也能通过变量赋值影响外部会话变量(如 @var)。
常见错误现象:ERROR 1312 (42000): PROCEDURE xxx can't return a result set in the given context(在触发器或函数里调用含 SELECT 的存储过程时触发);或 ERROR 1419 (HY000): You do not have the SUPER privilege(创建含 READS SQL DATA 等特性的存储过程时权限不足)。
- 参数类型支持
IN(默认)、OUT、INOUT,且可混用多个 - 允许事务控制(
START TRANSACTION、COMMIT、ROLLBACK) - 可执行任意 DML/DDL,包括临时表、游标、循环、条件判断
- 调用必须用独立语句:
CALL proc_name(arg1, @out_var),不能嵌在SELECT里
事务能力差异直接决定能否用于业务逻辑封装
如果你要实现「扣库存 + 写订单 + 记日志」这种多步操作并保证原子性,只能用存储过程——函数在 MySQL 中被禁止开启事务,哪怕加上 CONTAINS SQL 也无法绕过该限制。
- 函数内写
START TRANSACTION会报错:ERROR 1337 (42000): Variable 'autocommit' can't be set to NULL in stored function or trigger - 存储过程中可自由控制事务边界,配合
DECLARE EXIT HANDLER做异常回滚 - 函数适合纯计算场景:格式化时间、拼接字符串、数值转换等,不碰表数据
- 跨库操作(如
INSERT INTO db2.table SELECT ... FROM db1.table)只能放在存储过程中
权限和部署细节常被忽略
函数和存储过程都依赖 CREATE ROUTINE 权限,但启用它们还需全局开关:MySQL 默认关闭 log_bin_trust_function_creators,创建含 SQL 操作的函数时若未开此开关,会报 ERROR 1418。
- 生产环境部署前务必检查:
SELECT @@log_bin_trust_function_creators;,为0则需管理员执行SET GLOBAL log_bin_trust_function_creators = 1; - 函数名不能与系统函数同名(如
now、count),否则调用时优先匹配系统函数,自定义函数静默失效 - 存储过程的
SQL SECURITY设置影响执行上下文:设为DEFINER时按创建者权限运行,设为INVOKER则按调用者权限运行——权限模型不清晰时容易查不到数据 - 两者都不支持重载(同名不同参),重复创建会报错,删之前得先
DROP PROCEDURE IF EXISTS或DROP FUNCTION IF EXISTS
真正卡住人的从来不是语法,而是「该用函数的地方写了存储过程,结果发现没法在 WHERE 里调用」,或者「该用存储过程的地方写了函数,一加事务就崩」。边界必须划清:只算不改 → 函数;要改要控要多结果 → 存储过程。











