前言
在mysql开发中,很多新手会分不清存储过程、函数、触发器三者的定位。前面我们已经学习过mysql触发器、普通查询sql,今天我们单独把存储过程讲透,从概念、优缺点、基础语法、实战样例,再到使用场景与避坑点,全部一次性梳理清楚。
一、什么是存储过程
存储过程(stored procedure)是一组预先编译好的sql语句集合,存放在mysql数据库内部。
简单理解:把多条sql写在一起,给它起一个名字,后续直接调用这个名字就能一次性执行这一批sql,不需要重复编写一长串sql。
它和普通sql最大区别:普通sql每次执行都需要客户端发送、数据库解析编译;存储过程提前编译保存在服务端,调用时直接执行。
对比区分:
- 存储过程:可以没有返回值,支持in/out/inout参数,内部可以写复杂逻辑、事务,适合批量业务操作
- mysql函数:必须有返回值,多用于查询字段计算,不能直接使用事务
- 触发器:不需要手动调用,表发生增删改时自动触发
二、存储过程有什么作用
- 简化重复sql编写
业务中反复执行的多段sql,封装成存储过程,调用一行命令即可执行,减少代码冗余。 - 减少网络传输开销
多条sql封装在数据库服务端,客户端只发送一条调用指令,不用来回传输大量sql文本,网络交互变少。 - 统一业务逻辑
逻辑写在数据库层,所有应用端调用同一个存储过程,保证业务规则统一,修改逻辑只需要改存储过程,不用改多处业务代码。 - 支持复杂流程控制
内部支持if判断、while循环、游标、事务,可以实现单纯单条sql难以完成的复杂业务逻辑。
三、优缺点分析
✅ 优点
- 预编译,多次调用时性能有优势
- 批量操作、多表联动逻辑封装方便
- 权限可控,可以只开放存储过程调用权限,不开放底层表读写权限
❌ 缺点
- 调试困难,mysql没有很方便的断点调试工具
- 可移植性差,存储过程是数据库厂商特有语法,mysql和oracle不能直接复用
- 复杂业务写在数据库层,增加数据库压力,不利于应用水平扩展
- 版本管理麻烦,存储过程代码保存在数据库,不像业务代码可以直接用git管理
开发建议:简单批量逻辑可以使用;核心复杂业务逻辑,现代项目更多放在应用代码里。
四、基础语法与实战示例
语法模板
delimiter // -- 修改语句结束符,临时把;换成//,避免存储过程内的;提前结束定义
create procedure 存储过程名(
[in|out|inout] 参数名 参数类型
)
begin
-- 这里写sql逻辑
end //
delimiter ; -- 恢复默认结束符
参数类型说明:
in:入参,调用时传入,存储过程内部读取,不能修改传回(最常用)out:出参,存储过程内部赋值,调用结束后外部获取结果inout:既可传入,内部修改后又可以传出
示例1:无参数存储过程
沿用前面的学生表,查询所有及格学生:
delimiter //
create procedure proc_get_pass_student()
begin
select name,score from student where score >=60;
end //
delimiter ;
-- 调用存储过程
call proc_get_pass_student();
-- 删除存储过程
drop procedure if exists proc_get_pass_student;
示例2:带in输入参数
根据分数阈值,查询大于该分数的学生:
delimiter //
create procedure proc_get_student_by_score(in score_limit int)
begin
select name,score from student where score > score_limit;
end //
delimiter ;
-- 调用,查询分数大于80的学生
call proc_get_student_by_score(80);
示例3:in+out,带输出参数
传入分数下限,返回符合条件的总人数
delimiter //
create procedure proc_count_student(in score_limit int, out total int)
begin
select count(*) into total from student where score > score_limit;
end //
delimiter ;
-- 调用,@total是用户变量接收结果
call proc_count_student(60,@total);
select @total;
五、结合我们爬虫业务的实战样例
结合上一节spider.information表,封装一个存储过程:查询指定数据源列表、标题匹配年报esg关键词、近5年(time可为null)的数据。
业务场景:报表检索逻辑固定,每次只需要调用存储过程,不用重复粘贴一长串where条件。
delimiter //
create procedure proc_get_report_data()
begin
select
`id`,
`runs_id`,
`uuid`,
`title`,
`time`,
`title_href`,
`hash`,
`content_txt`,
`source`,
`status`,
`spider_name`,
`insert_time`,
`update_time`
from `spider`.`information`
where
(`time` is null or `time` >= date_sub(now(), interval 5 year))
and `source` in (
'andritz','danieli','fives','john cockerill','primetals',
'psi','sarralle','sms group','tenova'
)
and `title` regexp 'annual report|annual financial report|annual review|sustainability report|sustainable development report|esg report|environmental social and governance report|corporate social responsibility report|csr report|corporate responsibility report|integrated report|integrated annual report|annual integrated report|10-k|20-f|40-f|universal registration document|registration document|annual accounts'
order by `time` desc;
end //
delimiter ;
-- 调用
call proc_get_report_data();
如果想要支持动态传入关键词,可以改成带in参数版本,灵活传入检索关键词。
六、常用管理命令
-- 查看数据库下所有存储过程 show procedure status where db = 'spider'; -- 查看存储过程创建语句 show create procedure proc_get_report_data; -- 删除存储过程 drop procedure if exists proc_get_report_data;
七、适用场景与不推荐场景
✅ 适合使用存储过程:
- 跨多表的批量统计、报表查询,查询逻辑长期固定不变
- 数据库层面简单数据校验、批量数据更新
- 内部运维统计脚本,减少应用层代码编写
❌ 不推荐使用:
- 业务频繁迭代,经常修改查询条件
- 高并发互联网业务,大量复杂计算压在数据库
- 需要跨数据库迁移的项目
八、避坑要点
- delimiter 分隔符:定义存储过程前必须修改结束符,否则遇到
;就会终止创建语句,这是新手最容易踩的坑。定义完成记得恢复。 - 关键字作为字段名,一定要加反引号
`,比如time。 - out参数需要使用用户变量
@xxx接收,不能直接写普通变量。 - 存储过程不能在select里面直接调用,必须使用
call。 - 存储过程内部异常捕获需要手动写
declare handler,默认报错直接终止执行。
小结
存储过程本质就是sql脚本封装。在运维统计、固定报表场景非常好用,就像我们爬虫报表检索的例子,一次封装,反复调用。但在现代web业务开发中,不要盲目把业务逻辑全部下沉到数据库,要权衡维护成本和性能收益。
以上就是mysql数据库存储过程详解的详细内容,更多关于mysql数据库存储过程的资料请关注代码网其它相关文章!
发表评论