MySQL存储过程通过IN/OUT/INOUT参数传参和返回单值,多结果集用SELECT;变量须DECLARE声明,禁用未声明的@变量;事务需显式COMMIT/ROLLBACK;JDBC调用需配置预编译缓存和超时。

MySQL存储过程里怎么传参和返回结果
存储过程不是函数,RETURN 不能直接用;想把计算结果交还给应用,得靠 OUT 或 INOUT 参数,或者用 SELECT 输出结果集。应用层读取时,得按顺序匹配字段或参数名,别指望自动映射。
-
IN参数只进不出,适合传条件值(比如user_id) -
OUT参数只出不进,适合返回单个值(比如统计总数、状态码) -
INOUT可读可写,但容易混淆逻辑,除非真需要“原地改参”,否则少用 - 如果要返回多行多列数据,就用
SELECT,但注意:调用方必须能处理多结果集(比如 JDBC 需设allowMultiQueries=true)
为什么 CALL 一个存储过程会报 Unknown system variable 错误
常见于用了 MySQL 5.7+ 的新变量语法(比如 @var := xxx),但在存储过程里没声明变量类型或作用域。MySQL 存储过程里所有变量都得显式 DECLARE,且不能直接用用户变量 @xxx 替代局部变量。
- 错误写法:
SET @total = (SELECT COUNT(*) FROM orders);—— 这在过程体里不报错但不可靠,且无法被OUT参数引用 - 正确写法:
DECLARE total INT DEFAULT 0; SELECT COUNT(*) INTO total FROM orders; - 变量名和字段名别重名,否则
SELECT ... INTO可能意外覆盖局部变量 - MySQL 8.0+ 对变量作用域更严格,未声明就引用会直接报错
Unknown system variable
存储过程里事务控制要注意什么
MySQL 默认自动提交,但存储过程里一旦显式写 START TRANSACTION 或 BEGIN,后续所有 DML 都受控于你——包括没加 COMMIT 就退出,会导致连接挂着未提交事务,锁表、阻塞其他操作。
- 每个
START TRANSACTION必须配对COMMIT或ROLLBACK,别依赖外部连接的 autocommit - 异常没捕获时,事务不会自动回滚;要用
DECLARE EXIT HANDLER FOR SQLEXCEPTION包住关键块 - 避免在循环里反复
COMMIT,尤其是大批次更新——可能引发 binlog 增长过快、主从延迟 - DDL(如
ALTER TABLE)在事务中会隐式触发COMMIT,导致前面的 DML 提前提交,这点极易被忽略
Java 应用调用存储过程性能突然变差
不是存储过程本身慢,大概率是 JDBC 驱动没关预编译缓存,或没设超时,又或者过程里用了 SELECT 返回大量中间结果,被驱动全拉到内存里了。
- JDBC URL 加上
cachePrepStmts=true&prepStmtCacheSize=250,否则每次CALL都重新解析 - 给
CallableStatement设setQueryTimeout(),防止某个卡死的过程拖垮整个连接池 - 过程里避免
SELECT * FROM huge_table再加工——改成临时表 + 索引,或让应用分页查 - MySQL 服务端的
max_allowed_packet如果太小,大结果集会截断,报错像Packets larger than max_allowed_packet are not allowed
最麻烦的是嵌套调用:A 过程调 B,B 又调 C,每层都开事务、建临时表、查系统视图,监控时看不出瓶颈在哪。上线前得用 SHOW PROFILE 或 Performance Schema 抓真实执行路径,别光看平均耗时。


















