存储过程,存储函数

数据库中存储过程(Stored Procedure)存储函数(Stored Function) 的核心概念、区别以及实际用法


一、核心概念(以MySQL为例)

1. 存储过程(Stored Procedure)

可以把它理解为数据库中的"脚本/子程序",是一组为了完成特定功能的SQL语句集合,经编译后存储在数据库中。你可以通过调用它来执行这一系列SQL操作,支持传入参数、输出参数,也可以无参数。

  • 核心特点:执行一个"操作序列",重点在"过程/动作",返回值不是必需的(可以通过输出参数返回结果)。

2. 存储函数(Stored Function)

可以把它理解为数据库中的"自定义函数" ,也是一组SQL语句集合,但必须有返回值 (且只能返回一个值),可以像调用系统函数(如SUM()CONCAT())一样调用它。

  • 核心特点:计算并返回一个"结果值",重点在"计算/返回值",必须有返回值,且返回值类型需明确声明。

二、核心区别(新手必记)

特性 存储过程 存储函数
返回值 可选(可通过OUT参数返回多个值) 必须有(且仅返回一个值)
调用方式 使用CALL语句调用 可作为表达式一部分调用(如SELECT 函数名()
适用场景 执行复杂业务逻辑(增删改查组合) 计算并返回单个值(如自定义计算、数据转换)
能否包含事务 可以(如BEGIN/COMMIT/ROLLBACK) 不建议(通常用于简单计算,不处理事务)
参数类型 IN/OUT/INOUT(输入/输出/输入输出) 仅IN类型(输入参数)

三、实战示例(MySQL)

1. 存储过程示例(查询指定用户的订单数,通过OUT参数返回)

sql 复制代码
-- 创建存储过程:查询指定用户ID的订单总数
DELIMITER //  -- 临时修改语句结束符为//(避免与SQL中的;冲突)
CREATE PROCEDURE GetUserOrderCount(
    IN user_id INT,          -- 输入参数:用户ID
    OUT order_count INT      -- 输出参数:订单总数
)
BEGIN
    -- 核心逻辑:统计订单数并赋值给输出参数
    SELECT COUNT(*) INTO order_count 
    FROM orders 
    WHERE user_id = user_id;
END //
DELIMITER ;  -- 恢复语句结束符为;

-- 调用存储过程
SET @count = 0;  -- 定义变量接收输出结果
CALL GetUserOrderCount(1001, @count);  -- 调用:查询用户1001的订单数
SELECT @count;  -- 查看结果(如返回5,表示该用户有5个订单)

2. 存储函数示例(计算两个数的乘积)

sql 复制代码
-- 创建存储函数:计算两个数的乘积
DELIMITER //
CREATE FUNCTION CalculateProduct(
    num1 INT,  -- 输入参数1
    num2 INT   -- 输入参数2
) RETURNS INT  -- 声明返回值类型为INT
DETERMINISTIC  -- 确定性函数(相同输入必返回相同输出)
BEGIN
    RETURN num1 * num2;  -- 必须有RETURN语句返回值
END //
DELIMITER ;

-- 调用存储函数(像系统函数一样使用)
SELECT CalculateProduct(5, 8);  -- 输出:40
SELECT id, name, CalculateProduct(price, quantity) AS total FROM products;  -- 结合表查询

3. 存储过程的复杂示例(带事务的新增用户+订单)

sql 复制代码
-- 创建存储过程:新增用户并创建初始订单(包含事务)
DELIMITER //
CREATE PROCEDURE AddUserWithOrder(
    IN username VARCHAR(50),
    IN order_amount DECIMAL(10,2),
    OUT result VARCHAR(100)  -- 返回执行结果(成功/失败)
)
BEGIN
    DECLARE EXIT HANDLER FOR SQLEXCEPTION  -- 异常处理:出错则回滚
    BEGIN
        ROLLBACK;
        SET result = '失败:' || SQLSTATE || ' ' || SQLERRM;
    END;

    START TRANSACTION;  -- 开启事务

    -- 1. 新增用户
    INSERT INTO users (name) VALUES (username);
    -- 获取刚插入的用户ID
    SET @new_user_id = LAST_INSERT_ID();
    -- 2. 为该用户创建初始订单
    INSERT INTO orders (user_id, amount) VALUES (@new_user_id, order_amount);

    COMMIT;  -- 提交事务
    SET result = CONCAT('成功:用户', @new_user_id, '创建并生成初始订单');
END //
DELIMITER ;

-- 调用
SET @res = '';
CALL AddUserWithOrder('张三', 99.9, @res);
SELECT @res;  -- 查看执行结果

四、使用注意事项(新手避坑)

  1. 性能:存储过程/函数编译后存储,首次调用慢,后续调用快,适合高频执行的逻辑;但过度使用会增加数据库负担,建议仅用于核心业务逻辑。
  2. 可维护性:存储过程/函数写在数据库中,调试、版本管理不如应用代码方便,需结合业务场景选择(如简单计算用函数,复杂事务用过程)。
  3. 权限 :创建需要CREATE ROUTINE权限,调用需要EXECUTE权限,需注意数据库权限管控。
  4. 移植性:不同数据库(MySQL、Oracle、SQL Server)的语法差异较大(如Oracle的存储过程语法与MySQL不同),迁移成本高。

总结

  1. 存储过程 :侧重"执行动作/业务逻辑",支持输入/输出参数、事务,用CALL调用,无强制返回值,适合复杂的增删改查组合操作。
  2. 存储函数:侧重"计算并返回值",仅支持输入参数,必须返回单个值,可像系统函数一样调用,适合简单的数值/数据转换计算。
  3. 核心选择原则:需要返回单个值用函数 ,需要执行复杂逻辑(如事务、多步操作)用过程

你想了解数据库中游标(Cursor) 的核心概念、使用场景和具体用法,我会结合新手容易理解的例子(以MySQL为例),帮你搞清楚游标是什么、为什么用、怎么用,以及使用时的注意事项。


相关推荐
小高不会迪斯科6 小时前
CMU 15445学习心得(二) 内存管理及数据移动--数据库系统如何玩转内存
数据库·oracle
e***8907 小时前
MySQL 8.0版本JDBC驱动Jar包
数据库·mysql·jar
l1t7 小时前
在wsl的python 3.14.3容器中使用databend包
开发语言·数据库·python·databend
失忆爆表症8 小时前
03_数据库配置指南:PostgreSQL 17 + pgvector 向量存储
数据库·postgresql
AI_56788 小时前
Excel数据透视表提速:Power Query预处理百万数据
数据库·excel
SQL必知必会9 小时前
SQL 窗口帧:ROWS vs RANGE 深度解析
数据库·sql·性能优化
Gauss松鼠会9 小时前
【GaussDB】GaussDB数据库开发设计之JDBC高可用性
数据库·数据库开发·gaussdb
Vicky-Min9 小时前
NetSuite中保存Bill时遇到Overage的报错原因
oracle·erp
+VX:Fegn089510 小时前
计算机毕业设计|基于springboot + vue鲜花商城系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
识君啊10 小时前
SpringBoot 事务管理解析 - @Transactional 的正确用法与常见坑
java·数据库·spring boot·后端