MySQL 8.0 因默认启用 binlog 且 log_bin_trust_function_creators=0,强制要求函数显式声明 DETERMINISTIC、NO SQL 或 READS SQL DATA;5.6 则宽松允许缺失声明。

DETERMINISTIC、NO SQL、READS SQL DATA 这三个特性声明缺失,是 5.6 存储过程/函数在 8.0 中报错的最常见原因 —— 不是语法本身废止了,而是 8.0 在开启二进制日志(log_bin=ON)时强制要求显式声明函数行为。
为什么 5.6 能跑、8.0 就报错?
MySQL 5.6 对函数确定性声明是宽松的:只要没开 binlog,或开了但没设 log_bin_trust_function_creators=0(默认值),就允许不声明直接创建。而 MySQL 8.0 默认启用 binlog,且 log_bin_trust_function_creators 默认为 0,只要函数没带 DETERMINISTIC 等声明,就会直接拒绝创建或调用。
如何快速修复已有函数?
不需要重写逻辑,只需补全声明即可。注意:DETERMINISTIC 表示函数结果只依赖输入参数,NO SQL 表示不查也不改数据,READS SQL DATA 表示只读查询 —— 选最贴切的一个,不能乱填。
- 查出所有无声明的函数:
SELECT routine_schema, routine_name, routine_type FROM information_schema.routines WHERE routine_type = 'FUNCTION' AND (routine_definition NOT LIKE '%DETERMINISTIC%' AND routine_definition NOT LIKE '%NO SQL%' AND routine_definition NOT LIKE '%READS SQL DATA%'); - 用
ALTER FUNCTION补声明(示例):ALTER FUNCTION mydb.calc_total DETERMINISTIC; - 若函数实际会读表,必须用
READS SQL DATA;若纯计算,用DETERMINISTIC或NO SQL更安全
为什么不能简单设 log_bin_trust_function_creators=1?
这确实能绕过校验,但属于“掩耳盗铃”:
- 它只是关闭安全检查,不解决函数本身在复制环境下的不确定性风险
- 主从复制中,非确定性函数可能造成主从数据不一致,尤其涉及 NOW()、RAND()、USER() 等
- 8.0 后续小版本可能收紧该变量权限,或要求更细粒度控制
升级前怎么预防这类问题?
别等升级完才发现。在 5.6 环境里提前运行检查脚本,把声明补全:
- 导出函数定义:
mysqldump -u root -p --no-create-info --no-data --routines mydb > routines.sql - 用正则搜索
CREATE FUNCTION.*?BEGIN块,人工或脚本补上声明 - 在 5.7 中间版本验证:5.7 已开始预警,但还不强制;这是最后的低成本修复窗口
READS SQL DATA,在 8.0 的严格模式下仍可能因执行计划变更或事务隔离变化而行为偏移。这类逻辑得结合业务场景逐个压测。


















