站点导航
首页 网址导航 文章资讯 资源下载 问答社区 排行榜
数据库 详解 MySQL 存储过程:从创建、调用到删除完整指南
全文约 5532 字 · 阅读约 14 分钟
数据库

详解 MySQL 存储过程:从创建、调用到删除完整指南

神器小编 · 2026-09-28 11:00 104 阅读

本文通俗易懂讲解MySQL存储过程,附带大量可直接运行实战SQL示例。包含DELIMITER分隔符、IN/OUT/INOUT三种参数用法、变量声明、IF判断、WHILE循环、异常捕获,完整演示存储过程创建、查看、CALL调用与删除操作,分析存储过程优缺点和开发常见坑。

很多刚接触 MySQL 的开发者,写业务时会反复复制一大段相同的 SQL。比如每月统计订单、批量更新用户状态、汇总报表数据,每次都要在代码里拼接多条SQL,来回和数据库交互。不仅代码冗余,还会产生较多网络开销。MySQL 存储过程,就是用来解决这类重复数据操作的方案。

简单一句话理解:存储过程就是存放在 MySQL 服务器里面,提前写好的一段SQL脚本,给它起个名字,以后想用直接调用这个名字就行。

它把多条SQL、变量、判断、循环打包在一起,保存在数据库中。应用程序不需要每次把一长串SQL传给数据库,只需要发送一条调用指令,数据库就会执行内部全部逻辑。

很多人会混淆存储过程和函数:存储过程没有返回值,使用 CALL 调用,可以返回多个结果集;函数必须有返回值,可以直接嵌入SELECT语句中使用。

很多人会混淆存储过程和函数:存储过程没有返回值,使用 CALL 调用,可以返回多个结果集;函数必须有返回值,可以直接嵌入

一、写存储过程必须懂:分隔符 DELIMITER

MySQL 默认把英文分号 ; 当作一条SQL的结束标记。
普通单条SQL没问题,但是存储过程内部会写很多语句,每一句都带分号。如果不修改结束符,MySQL读到过程体内第一个;,就会误以为整条创建语句已经结束,直接报错。

所以写存储过程固定操作:

  1. 先用 DELIMITER 修改语句结束符号(常用 // 或者 $$)

  2. 编写 CREATE PROCEDURE 代码

  3. 存储过程写完,再用 DELIMITER ; 恢复默认分号

示例:

-- 修改结束符为 //
DELIMITER //

-- 这里写存储过程代码
CREATE PROCEDURE sp_test()
BEGIN
 SELECT 'hello mysql procedure';
END //

-- 恢复默认结束符
DELIMITER ;

这个是新手踩坑第一名,几乎所有写存储过程的初学者,都会忘记修改分隔符,导致创建失败。

这个是新手踩坑第一名,几乎所有写存储过程的初学者,都会忘记修改分隔符,导致创建失败。

二、创建存储过程语法详解 + 实战例子

基础创建语法:

CREATE PROCEDURE [IF NOT EXISTS] 存储过程名(参数列表)
BEGIN
 -- 这里写过程体,多条SQL逻辑
END

IF NOT EXISTS 可选,作用:如果同名存储过程已经存在,不会抛出错误,避免脚本执行中断。

存储过程三种参数(通俗讲解)

参数格式:参数方向 参数名称 数据类型,一共三类:

  • IN:输入参数(默认类型):外部传值进来,存储过程内部读取使用。过程内部修改这个变量,不会影响外面原始的值。相当于“只读传入”。

  • OUT:输出参数:只用来把计算结果传回外部。调用的时候必须传一个变量,存储过程内部给这个变量赋值,执行结束后外部可以读取结果。相当于“结果出口”。

  • INOUT:输入输出参数:既能传入初始值,存储过程内部修改之后,又把修改完的值返回出去。相当于双向通道。

开发小建议:参数名尽量加前缀 p_,避免和数据表字段重名,引发查询条件异常。

实例1:无参数存储过程

场景:有一张用户表 user,需要快速查询全部用户总数。每次统计都要写SELECT,封装成存储过程。

DELIMITER //
CREATE PROCEDURE sp_count_user()
BEGIN
 -- 查询用户总数
 SELECT COUNT(*) AS user_total FROM `user`;
END //
DELIMITER ;

解释:这个存储过程没有任何参数,调用之后直接返回用户表总记录数。

实例2:IN + OUT 参数组合(最常用)

场景:传入用户等级,自动统计该等级下一共有多少用户,把数量通过OUT参数返回。

DELIMITER //
CREATE PROCEDURE sp_get_user_by_level(IN p_level INT, OUT p_total INT)
BEGIN
 -- 根据传入等级,统计数量,存入输出变量p_total
 SELECT COUNT(*) INTO p_total FROM `user` WHERE level = p_level;
END //
DELIMITER ;
  • IN p_level INT:调用时传入等级数字,用来做查询条件

  • OUT p_total INT:执行完成之后,用户总数会存到这个变量里,供外部读取

实例3:INOUT 参数实战

场景:传入一个数字,在存储过程内部把数字乘以2,返回新数值。

DELIMITER //
CREATE PROCEDURE sp_inout_demo(INOUT p_num INT)
BEGIN
 SET p_num = p_num * 2;
END //
DELIMITER ;

调用的时候,变量既要带入初始值,又要接收计算之后的结果。

查看数据库里已有的存储过程

写好之后,可以查看存储过程列表,或者查看完整创建语句。

  1. 查询当前数据库所有存储过程

SHOW PROCEDURE STATUS WHERE Db = 'test_db';

test_db 替换成你自己的数据库名称。这条语句会展示存储过程名称、创建时间、字符集等信息。

  1. 查看存储过程完整创建代码

SHOW CREATE PROCEDURE sp_get_user_by_level;

适合时间久了,忘记存储过程内部逻辑的时候查看源码。

适合时间久了,忘记存储过程内部逻辑的时候查看源码。

三、调用存储过程:CALL关键字实战

所有存储过程统一使用 CALL 关键字调用。

调用无参存储过程

CALL sp_count_user();

执行之后,直接返回查询结果,和直接运行SELECT效果一样。

调用带IN、OUT参数存储过程

OUT参数不能直接写数字常量,必须使用MySQL用户变量接收,变量以@开头。

-- 调用存储过程,传入等级1,统计结果存入@res
CALL sp_get_user_by_level(1,@res);
-- 读取输出变量的值
SELECT @res;

执行流程:

  1. 把数字1传给p_level(IN参数)

  2. 存储过程内部统计level=1的用户数量

  3. 将数量赋值给OUT参数p_total

  4. p_total的值传递给外部变量@res

  5. SELECT @res,查看最终统计数字

调用INOUT参数存储过程

-- 设置初始值10,存入@num
SET @num = 10;
-- 调用存储过程
CALL sp_inout_demo(@num);
-- 查看结果,会得到20
SELECT @num;

执行流程:

  1. @num初始值10传入存储过程p_num

  2. 内部计算 p_num =10*2 =20

  3. INOUT会把修改后的20传回外部@num变量

四、存储过程内部:变量、判断、循环、异常捕获

稍微复杂一点的业务,单纯SELECT不够用,存储过程支持局部变量、if判断、while循环、异常捕获。

局部变量 DECLARE

DECLARE 用来声明局部变量,只在当前 BEGIN ... END 代码块内生效,离开这个代码块就失效。

重点规则:DECLARE 必须写在 BEGIN 的第一行区域,不能放在IF、循环语句后面,否则直接报错。

示例:

DELIMITER //
CREATE PROCEDURE sp_var_demo()
BEGIN
 -- 声明局部变量,设置默认值
 DECLARE v_name VARCHAR(50) DEFAULT '';
 DECLARE v_count INT DEFAULT 0;

 -- 变量赋值方式1:SET
 SET v_count = 100;
 -- 变量赋值方式2:SELECT ... INTO
 SELECT username INTO v_name FROM `user` WHERE id = 1;

 -- 输出查看变量
 SELECT v_name, v_count;
END //
DELIMITER ;

IF条件判断

场景:根据用户数量,判断数据规模,输出提示文字。

DELIMITER //
CREATE PROCEDURE sp_if_demo(IN p_count INT)
BEGIN
 IF p_count > 100 THEN
 SELECT '数据量超标';
 ELSEIF p_count > 10 THEN
 SELECT '数据量中等';
 ELSE
 SELECT '数据量很小';
 END IF;
END //
DELIMITER ;

调用测试:

CALL sp_if_demo(120);

WHILE循环语句

场景:循环累加数字,计算从1到传入数字的总和。

DELIMITER //
CREATE PROCEDURE sp_while_demo(IN p_max INT, OUT p_sum INT)
BEGIN
 DECLARE v_i INT DEFAULT 1;
 SET p_sum = 0;
 WHILE v_i <= p_max DO
 SET p_sum = p_sum + v_i;
 SET v_i = v_i + 1;
 END WHILE;
END //
DELIMITER ;

调用测试:

CALL sp_while_demo(10,@sum);
SELECT @sum; -- 输出55

异常处理 DECLARE HANDLER

执行SQL的时候有可能出错,比如查询数据不存在、主键冲突。DECLARE HANDLER 用来捕获异常,避免整个存储过程直接中断。

示例:捕获找不到数据的异常,返回提示:

DELIMITER //
CREATE PROCEDURE sp_handler_demo(IN p_uid INT)
BEGIN
 -- 如果查询不到数据,触发这个处理器
 DECLARE EXIT HANDLER FOR NOT FOUND
 BEGIN
 SELECT '没有找到对应用户';
 END;

 SELECT username FROM `user` WHERE id = p_uid;
END //
DELIMITER ;

调用 CALL sp_handler_demo(9999),如果id=9999不存在,不会抛出错误,而是返回提示文字。

调用 CALL sp_handler_demo(9999),如果id=9999不存在,不会抛出错误,而是返回提示文字。

五、删除存储过程

MySQL没有直接修改存储过程的命令 ALTER PROCEDURE,如果要修改存储过程逻辑,只能先删除旧的,再重新创建新版本。

删除语法:

DROP PROCEDURE [IF EXISTS] 存储过程名;

加上 IF EXISTS 是好习惯:当存储过程不存在的时候,不会抛出错误,批量脚本执行更稳定。

示例:

DROP PROCEDURE IF EXISTS sp_get_user_by_level;

六、存储过程优缺点,什么时候该用,什么时候尽量避免

存储过程优点

  1. SQL逻辑复用:相同统计、批量操作逻辑,多个项目、多个接口都可以调用,不用重复写SQL。

  2. 减少网络传输开销:应用只发送一条CALL命令,多条SQL逻辑在数据库内部执行,不用来回传输大量SQL文本。

  3. 精细化权限控制:可以不给开发账号开放表的直接读写权限,只允许调用指定存储过程,提升数据安全。

  4. 事务打包方便:批量新增、更新操作,可以直接在存储过程内部开启事务,保证一批数据同时成功或者回滚。

存储过程缺点

  1. 调试困难:MySQL原生没有断点调试工具,存储过程逻辑复杂时,排查BUG比较麻烦。

  2. 业务逻辑耦合在数据库:业务代码一部分写在程序里,一部分写在数据库存储过程,维护人员需要同时维护两处代码。项目迁移数据库版本时,存在兼容性风险。

  3. 数据库压力上升:大量计算逻辑放在MySQL服务端,高并发场景下,会消耗数据库CPU和内存,容易成为性能瓶颈。

  4. 版本管理麻烦:存储过程保存在数据库,不像代码文件可以直接用Git做版本管理,变更记录不好追溯。

✅ 推荐使用场景:

  • 固定周期批量数据统计、报表生成

  • 跨表批量数据同步、历史数据归档

  • 逻辑固定,多系统共用的数据操作

❌ 不推荐场景:

  • 业务频繁变动的核心业务逻辑

  • 超高并发接口,数据库本身压力很大

  • 需要频繁调试、迭代的业务

七、新手高频踩坑汇总

  1. 忘记修改DELIMITER分隔符:创建存储过程报语法错误,90%新手都是这个问题。写完一定要恢复 DELIMITER ;。

  2. 参数名称和数据表字段同名:例如参数写 IN p_level INT,字段也叫level,容易出现查询条件被覆盖,统计结果异常。

  3. OUT参数传常量:调用OUT参数时,不能直接写数字字符串,必须使用@开头的用户变量接收结果。

  4. DECLARE局部变量位置错误:局部变量声明必须放在BEGIN之后最前面,不能写在IF、循环后面。

  5. 存储过程创建成功,但调用返回空:大概率是查询条件写错,或者OUT变量没有正确赋值。

  6. 修改存储过程使用ALTER:MySQL不支持直接修改存储过程主体,只能DROP之后重新CREATE。

本文为作者原创,首发于神器阁社区。未经授权禁止转载;商业转载请联系作者获得授权,非商业转载请注明出处与原文链接。
神器小编 的头像
神器小编

资源创作者,欢迎关注。

24 资源 0 粉丝
相关推荐
全部评论 0
最热 最新
0/500
还没有评论,来说两句吧