oracle存储过程中无法用when语句直接捕获ora-00001,因其非预定义异常名,须在when others分支中通过sqlcode = -1判断并处理,且日志写入需自治事务保障。

Oracle存储过程里不能靠WHEN语句直接捕获ORA-00001这类错误码——它不是预定义异常名,而是运行时动态生成的SQLERRM内容。
WHEN语句只认预定义异常或自定义异常,不认ORA-错误码
Oracle的EXCEPTION块中WHEN子句只能匹配已声明的异常(如NO_DATA_FOUND)或用户自定义异常,不能写WHEN ORA-00001 THEN。ORA-开头的错误码是字符串,不是PL/SQL语言层面的异常标识符。
- 预定义异常(如
NO_DATA_FOUND、TOO_MANY_ROWS)有固定SQLCODE值,但仅覆盖常见场景,不包括所有ORA-错误 - ORA-00001、ORA-02291等约束类错误,在
WHEN OTHERS分支里才真正暴露 - 试图用
WHEN SQLCODE = -1 THEN语法会报编译错误——PL/SQL不支持在WHEN后直接判断SQLCODE
必须用WHEN OTHERS + SQLCODE做分支判断
捕获特定错误码的唯一可靠路径,是在WHEN OTHERS分支里读取SQLCODE和SQLERRM,再用IF做逻辑分发。
-
SQLCODE返回负整数(如ORA-00001对应-1),注意它不含前导零,直接比较即可 - 不要依赖
SQLERRM字符串匹配'ORA-00001'——某些环境可能截断或转义,而SQLCODE始终稳定 - 示例片段:
EXCEPTION WHEN OTHERS THEN IF SQLCODE = -1 THEN -- 处理唯一约束冲突 INSERT INTO TBL_PROC_ERRMSG (BIZ_CODE, ERR_LINE, ERR_CODE, MSG) VALUES ('USER_REG', DBMS_UTILITY.FORMAT_ERROR_BACKTRACE, 'ORA-00001', SQLERRM); COMMIT; ELSIF SQLCODE = -2291 THEN -- 处理外键约束失败 NULL; ELSE RAISE; -- 其他错误原样抛出 END IF;
自治事务是写日志的前提,否则COMMIT会破坏主事务
如果在异常处理里要往日志表(如TBL_PROC_ERRMSG)插入记录并COMMIT,必须把日志写入过程声明为自治事务,否则COMMIT会提前结束当前存储过程的事务上下文。
- 日志存储过程开头必须加:
PRAGMA AUTONOMOUS_TRANSACTION; - 写完日志后必须显式
COMMIT;,自治事务不继承主事务的提交/回滚状态 - 若忘记
PRAGMA,执行到COMMIT时会报错:ORA-06519: active autonomous transaction detected and rolled back - 不建议在
WHEN OTHERS里直接INSERT日志表——没自治事务保护,日志写不进去还可能掩盖原错误
DBMS_UTILITY.FORMAT_ERROR_BACKTRACE比行号更准,但需注意调用位置
DBMS_UTILITY.FORMAT_ERROR_BACKTRACE能给出精确到行的调用栈(如ORA-06512: at "SCOTT.PROC_USER_SAVE", line 47),但它返回的是“异常发生点”,不是EXCEPTION块所在行。
- 放在
WHEN OTHERS里调用,返回的是实际出错那行,比如INSERT语句所在行,不是EXCEPTION关键词那行 - 若存储过程嵌套调用,它会显示完整链路,比
SQLCODE更能定位深层问题 - 别和
DBMS_UTILITY.FORMAT_ERROR_STACK混淆:后者只返回第一层错误(类似SQLERRM),不带行号 - 生产环境记录日志时,优先用
FORMAT_ERROR_BACKTRACE而非SQLERRM,尤其当错误来自被调用的子过程时
真正难的不是写WHEN OTHERS,而是确保日志能落盘且不干扰业务逻辑——自治事务声明漏了、COMMIT忘了、或者把RAISE写成RAISE_APPLICATION_ERROR改了错误码,都会让排查变困难。











