oracle存储过程是什么意思

今天是2025年09月16日共有1人阅读

在 Oracle 数据库开发与运维中,存储过程是提升效率、简化复杂业务逻辑的核心工具。无论是 “创建存储过程”“调用执行”,还是 “循环与游标使用”“定时任务配置”,都是开发者高频需求。本文从基础概念到实战案例,系统拆解 Oracle 存储过程的关键操作,帮你快速上手并解决实际问题。

一、基础认知:什么是 Oracle 存储过程?

Oracle 存储过程是预编译后存储在数据库中的 PL/SQL 代码块,可封装复杂业务逻辑(如数据查询、批量更新、事务处理等),通过 “调用” 直接执行,无需重复编写 SQL。其核心优势包括:

1.提升效率:预编译一次,多次调用无需重新解析,减少数据库交互开销;

2.简化维护:业务逻辑集中在存储过程中,修改时只需更新存储过程,无需改动应用代码;

3.保障安全:可通过权限控制,让用户调用存储过程但不直接操作底层表,避免数据泄露;

4.支持事务:能统一管理事务(commit/rollback),确保业务操作的原子性。

二、核心操作:Oracle 存储过程的创建、调用与执行

这是开发者最常用的三大操作,以下结合语法规则和实例详细说明,确保零基础也能看懂。

1. 创建存储过程:语法与实例(解决 “oracle 创建存储过程”“oracle 存储过程写法” 需求)

(1)基本语法

创建存储过程的通用语法结构如下,需包含 “存储过程名、参数(可选)、PL/SQL 代码块、异常处理(可选)”:

CREATE OR REPLACE PROCEDURE 存储过程名(

    -- 参数列表:IN(输入参数,默认)、OUT(输出参数)、IN OUT(既输入又输出)

    参数1 数据类型 [IN/OUT/IN OUT] := 默认值,

    参数2 数据类型 [IN/OUT/IN OUT] := 默认值

) AS

    -- 声明部分:定义变量、常量、游标等(可选)

    变量名 数据类型;

BEGIN

    -- 执行部分:核心业务逻辑(必须)

    业务SQL/PL/SQL代码;    

EXCEPTION

    -- 异常处理部分:捕获并处理执行中的错误(可选)

    WHEN 异常类型 THEN

        错误处理逻辑;

END 存储过程名;

/ -- 结束符,执行存储过程创建

注意:CREATE OR REPLACE表示 “若存储过程已存在,则覆盖更新”,避免重复删除再创建的麻烦;参数的数据类型需符合 Oracle 规范(如VARCHAR2(50)、NUMBER(10),无需指定长度的如DATE)。

(2)实战实例:创建一个简单的存储过程

需求:创建存储过程P_GET_EMP_INFO,根据员工 ID(输入参数)查询员工姓名和薪资,并通过输出参数返回结果。

CREATE OR REPLACE PROCEDURE P_GET_EMP_INFO(

    P_EMP_ID IN NUMBER, -- 输入参数:员工ID

    P_EMP_NAME OUT VARCHAR2, -- 输出参数:员工姓名

    P_EMP_SAL OUT NUMBER -- 输出参数:员工薪资

) AS

BEGIN

    -- 从EMP表查询数据,赋值给输出参数

    SELECT ENAME, SAL 

    INTO P_EMP_NAME, P_EMP_SAL 

    FROM EMP 

    WHERE EMPNO = P_EMP_ID;

    

EXCEPTION

    -- 捕获“无数据找到”异常

    WHEN NO_DATA_FOUND THEN

        DBMS_OUTPUT.PUT_LINE('错误:未找到ID为' || P_EMP_ID || '的员工');

        P_EMP_NAME := NULL;

        P_EMP_SAL := NULL;

    -- 捕获其他所有异常

    WHEN OTHERS THEN

        DBMS_OUTPUT.PUT_LINE('执行错误:' || SQLERRM); -- 输出错误信息

END P_GET_EMP_INFO;

/

执行上述代码后,存储过程会保存到数据库中,可通过后续 “查询存储过程” 操作验证是否创建成功。

2. 调用与执行存储过程:3 种常用方式(解决 “oracle 执行存储过程”“oracle 调用存储过程” 需求)

存储过程创建后,需通过 “调用” 触发执行,不同场景对应不同调用方式,以下是最常用的 3 种:

(1)通过EXECUTE(或EXEC)调用(适合简单无输出参数或输出参数可忽略的场景)

若存储过程无输出参数(如仅执行数据插入 / 更新),可直接用EXEC调用:


-- 实例:调用存储过程P_INSERT_EMP(假设该存储过程无输出参数,仅插入员工数据)

EXEC P_INSERT_EMP(1001, '张三', '开发工程师', 8000);

/

(2)通过PL/SQL块调用(适合有输出参数,需接收结果的场景)

以之前创建的P_GET_EMP_INFO为例,需定义变量接收输出参数的结果:


DECLARE

    V_NAME VARCHAR2(50); -- 接收员工姓名的变量

    V_SAL NUMBER; -- 接收员工薪资的变量

BEGIN

    -- 调用存储过程,传入员工ID=7369,输出结果赋值给V_NAME和V_SAL

    P_GET_EMP_INFO(7369, V_NAME, V_SAL);

    

    -- 打印结果(需先开启DBMS_OUTPUT显示,执行SET SERVEROUTPUT ON)

    DBMS_OUTPUT.PUT_LINE('员工姓名:' || V_NAME);

    DBMS_OUTPUT.PUT_LINE('员工薪资:' || V_SAL);

END;

/

执行前需开启输出:在 PL/SQL Developer 或 SQL*Plus 中,先执行SET SERVEROUTPUT ON,否则无法看到DBMS_OUTPUT的打印结果。

(3)通过Java/Python等应用程序调用(适合项目开发中集成存储过程的场景)

以 Java 为例,通过 JDBC 调用 Oracle 存储过程,核心代码如下:


// 1. 加载驱动并建立数据库连接(省略连接代码)

Connection conn = ...;

// 2. 定义调用存储过程的SQL(?表示占位符,对应输入/输出参数)

String sql = "{call P_GET_EMP_INFO(?, ?, ?)}";

CallableStatement cstmt = conn.prepareCall(sql);

// 3. 设置输入参数(员工ID=7369)

cstmt.setInt(1, 7369);

// 4. 注册输出参数(指定参数类型)

cstmt.registerOutParameter(2, OracleTypes.VARCHAR); // 员工姓名(字符串)

cstmt.registerOutParameter(3, OracleTypes.NUMBER); // 员工薪资(数字)

// 5. 执行存储过程

cstmt.execute();

// 6. 获取输出结果

String empName = cstmt.getString(2);

double empSal = cstmt.getDouble(3);

System.out.println("员工姓名:" + empName);

System.out.println("员工薪资:" + empSal);

// 7. 关闭资源(省略)

3. 查询与查看存储过程:找到已创建的存储过程(解决 “oracle 查询存储过程”“oracle 查看存储过程” 需求)

创建存储后,若需查看其代码、状态或所属用户,可通过 Oracle 系统视图查询,常用方式如下:

(1)查看存储过程的基本信息(名称、所属用户、状态)

通过ALL_PROCEDURES(所有用户可访问的存储过程)或USER_PROCEDURES(当前用户的存储过程)视图查询:


-- 查看当前用户下所有存储过程的名称和状态

SELECT OBJECT_NAME AS 存储过程名, STATUS AS 状态 

FROM USER_PROCEDURES 

WHERE OBJECT_TYPE = 'PROCEDURE';

-- 查看指定存储过程(如P_GET_EMP_INFO)的所属用户和创建时间

SELECT OWNER AS 所属用户, OBJECT_NAME AS 存储过程名, CREATED AS 创建时间 

FROM ALL_PROCEDURES 

WHERE OBJECT_NAME = 'P_GET_EMP_INFO' 

  AND OBJECT_TYPE = 'PROCEDURE';

状态说明:VALID表示存储过程编译通过,可正常调用;INVALID表示编译失败(如依赖表被删除),需重新编译(执行ALTER PROCEDURE 存储过程名 COMPILE;)。

(2)查看存储过程的完整代码

通过USER_SOURCE(当前用户的存储过程源代码)或ALL_SOURCE视图查询,需按LINE排序(代码按行存储):


-- 查看当前用户下P_GET_EMP_INFO的完整代码

SELECT TEXT AS 存储过程代码 

FROM USER_SOURCE 

WHERE NAME = 'P_GET_EMP_INFO' 

  AND TYPE = 'PROCEDURE' 

ORDER BY LINE;

执行后,TEXT列会按行显示存储过程的所有代码,拼接后即可得到完整内容。

三、进阶实战:存储过程的循环、游标与返回值处理

在复杂业务场景中,“循环遍历数据”“游标处理结果集”“返回多组数据” 是高频需求,以下结合实例拆解关键操作。

1. 存储过程中的循环:3 种常用循环方式(解决 “oracle 存储过程循环” 需求)

Oracle 存储过程支持FOR循环、WHILE循环、LOOP循环,分别适用于不同场景:

(1)FOR 循环(适合已知循环次数的场景)

需求:循环插入 5 条测试数据到TEST_TABLE表(表结构:ID NUMBER, NAME VARCHAR2 (50)):


CREATE OR REPLACE PROCEDURE P_LOOP_INSERT

AS

BEGIN

    -- 循环5次(从1到5)

    FOR I IN 1..5 LOOP

        INSERT INTO TEST_TABLE (ID, NAME) 

        VALUES (I, '测试数据_' || I);

    END LOOP;

    COMMIT; -- 提交事务

    DBMS_OUTPUT.PUT_LINE('循环插入完成,共插入5条数据');

END P_LOOP_INSERT;

/

(2)WHILE 循环(适合未知循环次数,需判断条件的场景)

需求:查询EMP表中薪资小于 3000 的员工,循环更新其薪资(增加 10%),直到无符合条件的员工:


CREATE OR REPLACE PROCEDURE P_WHILE_UPDATE

AS

    V_COUNT NUMBER := 1; -- 计数器,初始为1(确保进入循环)

BEGIN

    -- 当存在薪资<3000的员工时,继续循环

    WHILE V_COUNT > 0 LOOP

        -- 更新薪资(增加10%)

        UPDATE EMP 

        SET SAL = SAL * 1.1 

        WHERE SAL < 3000 

          AND ROWNUM = 1; -- 每次更新1条,避免批量锁表

        

        -- 检查是否还有符合条件的员工

        SELECT COUNT(*) INTO V_COUNT 

        FROM EMP 

        WHERE SAL < 3000;

        

        DBMS_OUTPUT.PUT_LINE('当前剩余需更新员工数:' || V_COUNT);

    END LOOP;

    COMMIT;

    DBMS_OUTPUT.PUT_LINE('薪资更新完成');

END P_WHILE_UPDATE;

/

2. 存储过程中的游标:处理结果集(解决 “oracle 存储过程游标” 需求)

游标是 “指向结果集的指针”,用于在存储过程中遍历查询结果集(如批量处理多条数据),分为显式游标和隐式游标,显式游标需手动定义,适用于复杂结果集处理:

实例:用显式游标批量处理员工数据

需求:创建存储过程P_CURSOR_PROC,查询EMP表中部门编号为 30 的员工,打印每个员工的姓名和薪资,并统计该部门总人数:


CREATE OR REPLACE PROCEDURE P_CURSOR_PROC

AS

    -- 1. 定义游标:指定查询结果集

    CURSOR C_EMP IS 

        SELECT ENAME, SAL 

        FROM EMP 

        WHERE DEPTNO = 30;

    

    -- 2. 定义变量,用于接收游标中的每行数据

    V_ENAME VARCHAR2(50);

    V_SAL NUMBER;

    V_TOTAL NUMBER := 0; -- 统计总人数

BEGIN

    -- 3. 打开游标

    OPEN C_EMP;

    

    -- 4. 循环提取游标数据(FETCH ... INTO 接收变量)

    LOOP

        FETCH C_EMP INTO V_ENAME, V_SAL;

        EXIT WHEN C_EMP%NOTFOUND; -- 当游标无数据时,退出循环

        

        -- 打印当前员工信息

        DBMS_OUTPUT.PUT_LINE('员工姓名:' || V_ENAME || ',薪资:' || V_SAL);

        V_TOTAL := V_TOTAL + 1; -- 计数+1

    END LOOP;

    

    -- 5. 关闭游标

    CLOSE C_EMP;

    

    -- 打印统计结果

    DBMS_OUTPUT.PUT_LINE('部门30总员工数:' || V_TOTAL);

END P_CURSOR_PROC;

/

执行结果:调用该存储过程后,会依次打印部门 30 的所有员工信息,最后输出总人数,适合批量处理有明确条件的结果集。

3. 存储过程的返回值:3 种实现方式(解决 “oracle 存储过程返回值” 需求)

Oracle 存储过程本身不直接支持 “return 返回值”,需通过输出参数、游标、自定义函数(FUNCTION) 实现返回数据的需求,以下是常用方式:

(1)通过 OUT 参数返回单个值(适合返回单个结果,如统计数、状态码)

实例:创建存储过程P_GET_DEPT_COUNT,根据部门编号返回该部门的员工总数:


CREATE OR REPLACE PROCEDURE P_GET_DEPT_COUNT(

    P_DEPTNO IN NUMBER, -- 输入参数:部门编号

    P_COUNT OUT NUMBER -- 输出参数:返回员工总数

) AS

BEGIN

    SELECT COUNT(*) INTO P_COUNT 

    FROM EMP 

    WHERE DEPTNO = P_DEPTNO;

EXCEPTION

    WHEN OTHERS THEN

        P_COUNT := 0; -- 异常时返回0

        DBMS_OUTPUT.PUT_LINE('查询错误:' || SQLERRM);

END P_GET_DEPT_COUNT;

/

调用时通过变量接收P_COUNT,即可获取返回的员工总数。

(2)通过游标返回多组数据(适合返回多条结果,如查询列表)

实例:创建存储过程P_GET_EMP_LIST,根据薪资范围返回符合条件的员工列表(用游标输出):


CREATE OR REPLACE PROCEDURE P_GET_EMP_LIST(

    P_MIN_SAL IN NUMBER, -- 输入参数:最低薪资

    P_MAX_SAL IN NUMBER, -- 输入参数:最高薪资

    P_EMP_CURSOR OUT SYS_REFCURSOR -- 输出参数:游标(返回员工列表)

) AS

BEGIN

    -- 打开游标,将查询结果集赋值给游标

    OPEN P_EMP_CURSOR FOR

        SELECT EMPNO, ENAME, SAL, DEPTNO 

        FROM EMP 

        WHERE SAL BETWEEN P_MIN_SAL AND P_MAX_SAL;

END P_GET_EMP_LIST;

/

调用时,通过SYS_REFCURSOR类型的变量接收游标,再遍历游标获取多条员工数据。

(3)通过 FUNCTION 替代(适合需直接返回单个值,类似 “函数调用” 的场景)

若需像 “函数” 一样直接返回值(如SELECT 函数名(参数) FROM DUAL),可创建FUNCTION(本质是特殊的存储过程,支持 return):


-- 创建函数F_GET_EMP_SAL,根据员工ID返回薪资

CREATE OR REPLACE FUNCTION F_GET_EMP_SAL(

    P_EMP_ID IN NUMBER

) RETURN NUMBER -- 指定返回值类型

AS

    V_SAL NUMBER;

BEGIN

    SELECT SAL INTO V_SAL 

    FROM EMP 

    WHERE EMPNO = P_EMP_ID;

    RETURN V_SAL; -- 直接返回薪资

EXCEPTION

    WHEN NO_DATA_FOUND THEN

        RETURN 0;

    WHEN OTHERS THEN

        RETURN -1; -- 异常时返回-1

END F_GET_EMP_SAL;

/

-- 调用函数:直接查询返回值

SELECT F_GET_EMP_SAL(7369) AS 员工薪资 FROM DUAL;

四、高频需求:删除存储过程与定时执行

除了基础操作,“删除无用存储过程” 和 “定时执行存储过程” 也是常见需求,以下是具体实现:

1. 删除存储过程(解决 “oracle 删除存储过程” 需求)

若存储过程不再使用,可通过DROP PROCEDURE删除,语法简单:


-- 删除存储过程P_OLD_PROC(若存在则删除)

DROP PROCEDURE IF EXISTS P_OLD_PROC</doubaocanvas>

oracle存储过程的分词解释

拼音:cún

1.存在;生存:残~。父母俱~。2.储存;保存:...查看详细解释

拼音:chǔ

储藏;存放:~蓄。~金。~粮备荒。已经确定为继承...查看详细解释

拼音:guò guo guō

[guò]表示经历、跨越、由甲至乙的过程。路...查看详细解释

拼音:chéng

规章;法式:章~。~式。道路;路段:登~。送了一...查看详细解释