企业级存储过程命名须以usp_为前缀、动词+名词结构,参数需显式声明方向与类型,错误处理须覆盖多种异常并使用raise_application_error,游标返回必须通过包中定义的ref cursor类型。

命名必须带前缀且动词+名词结构
存储过程名不是随便起的,usp_CreateOrder 和 proc_update_user 这类名字在企业级项目里会被直接拒收。前者明确表达“用户存储过程”+“动作+目标”,后者缺少前缀、动词小写、下划线风格不统一,容易和表名或函数混淆。
实际执行时要注意三点:
- 统一用
usp_(user stored procedure)开头,不用sp_(系统保留前缀,可能触发额外元数据查询) - 动词用过去式或现在式均可,但团队内必须一致;推荐用
usp_GetCustomerList而非usp_CustomerGetList - 避免缩写,比如
usp_UpdCust是反例;usp_UpdateCustomerProfile才算合格
参数定义必须显式声明方向与类型
写成 @DeviceID INT 是基础,但企业规范要求更严:所有参数必须标注 IN、OUT 或 IN OUT,哪怕默认是 IN。Oracle 和 PostgreSQL 对此强制,SQL Server 虽允许省略,但代码审查会打回。
常见踩坑点:
-
@IsPrecis VARCHAR2(1)没写长度 → 编译失败(Oracle)或隐式截断(SQL Server) -
@cus OUT CURSOR直接写CURSOR→ 报错,必须用包定义的types.cursorType - 输出参数未在调用端声明为
OUTPUT→ 值传不出来,但不报错,极易漏测
错误处理不能只捕获 NO_DATA_FOUND
只写 WHEN NO_DATA_FOUND THEN ... 是新手写法。真实业务中,ORA-01422(too many rows)、ORA-00942(表不存在)、ORA-06502(数值精度超限)都可能在线上爆发。只处理一个异常,等于没处理。
可靠做法是:
- 每个独立 DML 或 SELECT 块外层套
BEGIN ... EXCEPTION ... END,避免异常穿透影响后续逻辑 - 必须包含
WHEN OTHERS THEN,且里面至少记录SQLCODE和SQLERRM - 不要裸写
RAISE,要用RAISE_APPLICATION_ERROR(-20001, 'xxx')带业务码,方便应用层映射
游标返回必须用 REF CURSOR 类型
想让存储过程返回多行结果集?别用临时表或字符串拼接。企业级唯一合规方式是通过 REF CURSOR 输出。但直接写 TYPE cursorType IS REF CURSOR 会出问题——这个类型必须定义在包(package)里,不能放在过程体内。
正确结构分两步:
- 先建包:
CREATE OR REPLACE PACKAGE types AS TYPE cursorType IS REF CURSOR; END; - 再写过程:
CREATE OR REPLACE PROCEDURE select_li(cus OUT types.cursorType) IS BEGIN OPEN cus FOR SELECT * FROM tab; END;
漏掉包定义,或者把类型声明写在过程里,Oracle 会报 PLS-00320 错误,而且这个错误不提示具体哪一行,只说“类型不完整”,排查成本很高。











