MySQL从5.0版本开始引入存储过程和函数,将复杂SQL逻辑打包成可复用单元,提高重用性、减少网络传输并增强安全性。函数有返回值,存储过程无返回值。参数类型包括IN、OUT和INOUT,通过CALL语句调用。
MySQL从5.0版本开始引入了存储过程和函数,这一特性在数据库领域具有重要的进步意义。

长期稳定更新的攒劲资源: >>>点此立即查看<<<
存储过程和函数的核心作用是将复杂的SQL逻辑封装成一个可复用的单元。应用程序无需关注底层的SQL细节,只需像调用普通函数或执行命令一样调用它即可。
二者基本区别在于:函数必须有返回值,而存储过程没有。当然,这是最直观的区分,后续会展开更多细节。
含义:存储过程是一组预先编译好的SQL语句,打包存储在服务器上。英文名为Stored Procedure,直译为“存好的过程”。
执行过程:存储过程预先存储在MySQL服务器中,客户端只需发出调用命令,服务器便会执行预先存储的全部SQL语句。
好处:存储过程具有以下优势:
与视图、函数的对比:
存储过程的参数类型有三种:IN、OUT和INOUT。根据参数类型可分为以下几类:
注意:IN、OUT、INOUT可同时出现在一个存储过程中,且可带多个。
语法格式如下:
CREATE PROCEDURE 存储过程名(IN|OUT|INOUT 参数名 参数类型,...)
[characteristics ...]
BEGIN
存储过程体
END
# 调用
CALL 存储过程名();
编写存储过程时需注意以下几点:
IN:输入参数,存储过程只读取该参数的值。未定义参数种类时默认为IN。OUT:输出参数,存储过程执行完成后,调用方可读取参数中返回的值。INOUT:既是输入又是输出,调用时携带值,执行后可能改变。characteristics是存储过程的约束条件,主要包括:
LANGUAGE SQL:说明存储过程体由SQL语句组成,当前系统仅支持SQL。[NOT] DETERMINISTIC:指明结果是否确定。确定时相同输入得到相同输出;不确定时相同输入可能得到不同输出;默认不确定。{CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA}:说明子程序使用SQL语句的限制,默认是CONTAINS SQL。SQL SECURITY {DEFINER | INVOKER}:执行权限。DEFINER表示仅创建者可执行,INVOKER表示有访问权限的用户均可执行,默认DEFINER。COMMENT 'string':注释信息,用于描述存储过程。DELIMITER修改结束符,编写完成后再恢复。例如:
DELIMITER //将结束符改为//。DELIMITER ;恢复默认结束符。存储过程体为普通查询语句,使用CALL调用。例如:
DELIMITER $
CREATE PROCEDURE select_all_data()
BEGIN
SELECT * FROM emps;
END $
DELIMITER ;
# 调用
CALL select_all_data();
SELECT结果通过INTO赋值给变量。调用时传入@变量名,再通过SELECT查看变量值。例如:
DELIMITER //
CREATE PROCEDURE show_min_salary(OUT ms DOUBLE)
BEGIN
SELECT MIN(salary) INTO ms FROM emps;
END //
DELIMITER ;
# 调用
CALL show_min_salary(@ms);
SELECT @ms;
传入参数作为筛选条件。调用时可直接传值,也可传入@变量名。例如:
DELIMITER //
CREATE PROCEDURE show_someone_salary(IN empname VARCHAR(20))
BEGIN
SELECT salary FROM emps WHERE ename = empname;
END //
DELIMITER ;
# 调用方式1
CALL show_someone_salary('Abel');
# 调用方式2
SET @empname = 'Abel';
CALL show_someone_salary(@empname);
组合IN和OUT——输入员工姓名,输出员工薪资。例如:
DELIMITER //
CREATE PROCEDURE show_someone_salary2(IN empname VARCHAR(20), OUT empsalary DOUBLE)
BEGIN
SELECT salary INTO empsalary FROM emps WHERE ename = empname;
END //
DELIMITER ;
参数既是输入也是输出,执行后参数值会被修改。例如:
DELIMITER //
CREATE PROCEDURE show_mgr_name(INOUT empname VARCHAR(20))
BEGIN
SELECT ename INTO empname FROM emps WHERE eid = (SELECT MID FROM emps WHERE ename=empname);
END //
DELIMITER ;
存储过程必须使用CALL语句调用。要调用其他数据库的存储过程,需指定数据库名称,如CALL dbname.procname。
不同参数模式的调用方式如下:
CALL sp1('值');SET @name; CALL sp1(@name); SELECT @name;SET @name=值; CALL sp1(@name); SELECT @name;实用示例:实现累加运算,计算1+2+...+n的结果。
DELIMITER //
CREATE PROCEDURE `add_num`(IN n INT)
BEGIN
DECLARE i INT;
DECLARE sum INT;
SET i = 1;
SET sum = 0;
WHILE i <= n DO
SET sum = sum + i;
SET i = i + 1;
END WHILE;
SELECT sum;
END //
DELIMITER ;
CALL add_num(50);
MySQL存储过程缺乏类似Java或C++的专用IDE调试工具。常用方法是print调试法——使用SELECT语句输出中间结果,验证SQL正确性。调试成功后将SELECT语句后移,继续调试后续语句。也可将存储过程中的SQL复制出来逐段单独调试。
值得注意的是,调试过程较为繁琐,意味着维护成本较高。因此在实际生产环境中,通常不推荐大量使用存储过程。
MySQL支持自定义函数,定义后调用方式与内置函数类似。
CREATE FUNCTION 函数名(参数名 参数类型,...)
RETURNS 返回值类型
[characteristics ...]
BEGIN
函数体 # 函数体中必须包含 RETURN 语句
END
说明:
RETURNS type必须指定返回类型,函数体内必须包含RETURN value语句。调用方式与系统函数相同:SELECT 函数名(实参列表)
例如创建一个函数,查询某人的email:
DELIMITER //
CREATE FUNCTION email_by_name() RETURNS VARCHAR(25)
DETERMINISTIC CONTAINS SQL
BEGIN
RETURN (SELECT email FROM employees WHERE last_name = 'Abel');
END //
DELIMITER ;
SELECT email_by_name();
注意事项:
RETURNS(带S),但函数体内的RETURN不带S。DETERMINISTIC和CONTAINS SQL。SET GLOBAL log_bin_trust_function_creators = 1;。| 关键字 | 调用语法 | 返回值 | 应用场景 | |
|---|---|---|---|---|
| 存储过程 | PROCEDURE | CALL 存储过程() | 理解为有0个或多个 | 一般用于更新 |
| 存储函数 | FUNCTION | SELECT 函数() | 只能是一个 | 一般用于查询结果为一个值并返回时 |
存储过程没有传统意义上的返回值,而是通过OUT参数“修改”变量的值。此外,存储函数可放在查询语句中使用,存储过程不行。反之,存储过程功能更强大,能执行创建表、删除表、事务操作等——这些存储函数无法实现。
创建完成后,可通过以下方式查看已编写的存储过程:
SHOW CREATE FUNCTION test_db.CountProc \GSHOW PROCEDURE STATUS LIKE 'pattern',可列出所有存储过程或函数的信息。SELECT * FROM information_schema.Routines WHERE ROUTINE_NAME='存储过程或函数的名'。若存储过程和函数名称相同,需添加AND ROUTINE_TYPE = 'PROCEDURE'或'FUNCTION'加以区分。修改存储过程或函数并非修改功能和逻辑,而是修改相关特性。语法如下:
ALTER {PROCEDURE | FUNCTION} 存储过程或函数的名 [characteristic ...]
可修改的特性包括:
CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATASQL SECURITY {DEFINER | INVOKER}COMMENT 'string'例如:
ALTER PROCEDURE CountProc MODIFIES SQL DATA SQL SECURITY INVOKER ;
删除存储过程或函数使用DROP语句:
DROP {PROCEDURE | FUNCTION} [IF EXISTS] 存储过程或函数的名
IF EXISTS可防止因对象不存在而报错。
存储过程是否应该使用?业界存在不同观点。部分公司强制要求大型项目使用存储过程,而另一些公司则在开发手册中明确禁止。为何存在如此大的差异?
尽管有上述优点,但也存在替代方案。例如阿里巴巴的开发规范中明确规定:
【强制】禁止使用存储过程,存储过程难以调试和扩展,更没有移植性。
具体缺点包括:
小结:存储过程是一把双刃剑——使用方便,但也有局限。不同公司态度各异,但作为开发人员,掌握存储过程仍是必备技能之一。理解其工作原理及解决范围,是基本功。
侠游戏发布此文仅为了传递信息,不代表侠游戏网站认同其观点或证实其描述