PL/SQL 包(PACKAGE)¶
本章系统讲解 PL/SQL 包(PACKAGE) 的设计与使用。 包是大型 PL/SQL 项目(金融、账务、请求书系统)的核心组织单元,用于封装接口、隐藏实现、提升性能与可维护性,是面试必考内容。
1. 为什么项目一定要用 PACKAGE¶
在真实项目中,单独的过程/函数会迅速失控,PACKAGE 能解决:
- 接口与实现分离:对外只暴露规范(SPEC)
- 统一命名空间:避免同名冲突
- 隐藏私有逻辑:只在 BODY 内可见
- 性能优势:一次加载,减少解析与 I/O
- 版本可控:只改 BODY 不影响调用方
2. PACKAGE 的基本结构¶
PACKAGE 由两部分组成:
| 组成 | 作用 |
|---|---|
| PACKAGE SPEC | 对外声明(接口) |
| PACKAGE BODY | 具体实现(逻辑) |
📌 原则:
- 调用方只依赖 SPEC
- 实现细节全部放在 BODY
3. PACKAGE SPEC(规范)¶
3.1 规范中可以声明什么¶
- 公共常量
- 公共变量(慎用)
- 公共过程(PROCEDURE)
- 公共函数(FUNCTION)
- 类型定义(TYPE / SUBTYPE)
示例:PACKAGE SPEC¶
create or replace package pkg_account is
-- 常量
c_max_amount constant number := 10000;
-- 公共函数
function f_calc_fee(p_amount number) return number;
-- 公共过程
procedure p_transfer(
p_from in number,
p_to in number,
p_amt in number
);
end pkg_account;
/
4. PACKAGE BODY(实现)¶
4.1 BODY 中可以额外定义什么¶
- 私有过程 / 函数(SPEC 中未声明)
- 私有变量
- 私有类型
示例:PACKAGE BODY¶
create or replace package body pkg_account is
-- 私有函数(外部不可见)
function f_internal_check(p_amt number) return boolean is
begin
return p_amt <= c_max_amount;
end;
function f_calc_fee(p_amount number) return number is
begin
return p_amount * 0.02;
end;
procedure p_transfer(
p_from in number,
p_to in number,
p_amt in number
) is
begin
if not f_internal_check(p_amt) then
raise_application_error(-20001, 'Amount exceeds limit');
end if;
update account set balance = balance - p_amt where id = p_from;
update account set balance = balance + p_amt where id = p_to;
end;
end pkg_account;
/
5. 调用 PACKAGE 中的过程与函数¶
调用过程¶
begin
pkg_account.p_transfer(1, 2, 500);
end;
/
调用函数¶
declare
v_fee number;
begin
v_fee := pkg_account.f_calc_fee(1000);
end;
/
6. PACKAGE 初始化块(Initialization Section)¶
PACKAGE BODY 中可以包含 初始化代码,在第一次引用包时执行一次。
create or replace package body pkg_init is
g_start_time timestamp;
begin
g_start_time := systimestamp;
end pkg_init;
/
📌 特点:
- 每个会话(Session)执行一次
- 常用于缓存、初始化变量
7. PACKAGE 与权限管理(项目实务)¶
grant execute on pkg_account to app_user;
📌 项目中:
- 应用账号只授予 PACKAGE 的 EXECUTE 权限
- 不直接开放表的 DML 权限
8. PACKAGE 的常见设计规范¶
- 一个业务域一个 PACKAGE
- PACKAGE 名以
pkg_开头 - 过程名以
p_,函数名以f_ - 只在 SPEC 暴露必要接口
- 禁止在 SPEC 中声明可变全局变量
9. PACKAGE vs 单独 PROCEDURE / FUNCTION¶
| 项目 | PACKAGE | 单独对象 |
|---|---|---|
| 组织能力 | 强 | 弱 |
| 私有逻辑 | 支持 | 不支持 |
| 性能 | 更好 | 一般 |
| 可维护性 | 高 | 低 |
10. 项目实践总结¶
- 核心业务逻辑 必须放在 PACKAGE 中
- 对外接口稳定,内部实现可随时调整
- PACKAGE 是大型 PL/SQL 项目的基础设施
11. 本章小结(¶
- PACKAGE 由 SPEC 与 BODY 组成
- SPEC 定义接口,BODY 实现逻辑
- 支持私有过程/函数
- 提升可维护性与性能
- 项目中强烈推荐使用 PACKAGE