在MySQL开发中,很多新手会分不清存储过程、函数、触发器三者的定位。前面我们已经学习过MySQL触发器、普通查询SQL,今天我们单独把存储过程讲透,从概念、优缺点、基础语法、实战样例,再到使用场景与避坑点,全部一次性梳理清楚。
存储过程(Stored Procedure)是一组预先编译好的SQL语句集合,存放在MySQL数据库内部。
简单理解:把多条SQL写在一起,给它起一个名字,后续直接调用这个名字就能一次性执行这一批SQL,不需要重复编写一长串SQL。
它和普通SQL最大区别:普通SQL每次执行都需要客户端发送、数据库解析编译;存储过程提前编译保存在服务端,调用时直接执行。
对比区分:
- 存储过程:可以没有返回值,支持IN/OUT/INOUT参数,内部可以写复杂逻辑、事务,适合批量业务操作
- MySQL函数:必须有返回值,多用于查询字段计算,不能直接使用事务
- 触发器:不需要手动调用,表发生增删改时自动触发
? 优点
? 缺点
开发建议:简单批量逻辑可以使用;核心复杂业务逻辑,现代项目更多放在应用代码里。
|
1 2 3 4 5 6 7 8 |
DELIMITER // -- 修改语句结束符,临时把;换成//,避免存储过程内的;提前结束定义 CREATE PROCEDURE 存储过程名( [IN|OUT|INOUT] 参数名 参数类型 ) BEGIN -- 这里写SQL逻辑 END // DELIMITER ; -- 恢复默认结束符 |
参数类型说明:
沿用前面的学生表,查询所有及格学生:
|
1 2 3 4 5 6 7 8 9 10 11 12 |
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; |
根据分数阈值,查询大于该分数的学生:
|
1 2 3 4 5 6 7 8 9 |
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); |
传入分数下限,返回符合条件的总人数
|
1 2 3 4 5 6 7 8 9 10 |
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条件。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
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参数版本,灵活传入检索关键词。
|
1 2 3 4 5 6 7 8 |
-- 查看数据库下所有存储过程 SHOW PROCEDURE STATUS WHERE Db = 'spider';
-- 查看存储过程创建语句 SHOW CREATE PROCEDURE proc_get_report_data;
-- 删除存储过程 DROP PROCEDURE IF EXISTS proc_get_report_data; |
? 适合使用存储过程:
? 不推荐使用:
存储过程本质就是SQL脚本封装。在运维统计、固定报表场景非常好用,就像我们爬虫报表检索的例子,一次封装,反复调用。但在现代Web业务开发中,不要盲目把业务逻辑全部下沉到数据库,要权衡维护成本和性能收益。