不加EXCEPTION WHEN OTHERS时,存储过程遇错(如ORA-01403、ORA-00001)会立即中断,事务不自动回滚,数据可能处于不一致中间状态,且调用方仅收到模糊ORA错误,难以区分业务异常与系统故障。
存储过程没加 EXCEPTION WHEN OTHERS 会怎样
不加异常处理的存储过程,一旦 sql 报错(比如 ora-01403: no data found、ora-00001: unique constraint violated),会直接中断执行,事务不会自动回滚,已修改的数据可能处于中间状态。更危险的是,调用方(如 java/c# 应用)收到的是模糊的 ora 错误,无法区分是业务逻辑失败还是数据库连接断开。
EXCEPTION WHEN OTHERS 必须配合 ROLLBACK 吗
不是“必须”,但绝大多数场景下应该配。关键看事务边界是否由存储过程自身控制:
- 如果过程内含
COMMIT或SAVEPOINT,那WHEN OTHERS里要显式ROLLBACK TO savepoint_name或ROLLBACK - 如果过程只做 DML 不提交(由调用方统一控制事务),那
WHEN OTHERS里通常只记录日志 +RAISE,把错误原样抛出 - 盲目在
WHEN OTHERS里写ROLLBACK可能覆盖调用方的事务意图,反而破坏一致性
如何记录错误又不掩盖原始堆栈
直接 DBMS_OUTPUT.PUT_LINE 或插入日志表容易丢掉关键上下文。正确做法是用 DBMS_UTILITY.FORMAT_ERROR_BACKTRACE 拿到完整调用链:
EXCEPTION
WHEN OTHERS THEN
INSERT INTO proc_error_log (
proc_name, error_code, error_msg, backtrace, log_time
) VALUES (
$$PLSQL_UNIT,
SQLCODE,
SQLERRM,
DBMS_UTILITY.FORMAT_ERROR_BACKTRACE(),
SYSDATE
);
RAISE; -- 不吞掉异常,保留原始错误号和行号
END;注意:$$PLSQL_UNIT 是编译时变量,比硬编码过程名更可靠;RAISE 不带参数才能透传原始错误信息。
哪些错误不该被 WHEN OTHERS 捕获
WHEN OTHERS 是兜底,不是万能过滤器。以下三类错误建议单独处理或放任上抛:
-
NO_DATA_FOUND:这是正常业务分支,比如查用户不存在,应单独WHEN NO_DATA_FOUND THEN ... -
TOO_MANY_ROWS:说明 SQL 语义有歧义,该修查询而非捕获 - 系统级错误如
ORA-04031(共享池内存不足)、ORA-01555(快照过旧):这类问题需 DBA 干预,程序层捕获后也无力修复,记录即可
真正需要兜底的,是那些不可预测但不影响数据库稳定的业务异常——比如外部接口超时触发的自定义异常,或数据校验失败引发的 RAISE_APPLICATION_ERROR(-20001, '金额不能为负')。


















