RAISE_APPLICATION_ERROR是唯一能被客户端捕获为自定义异常的PL/SQL过程,需在可执行块中调用,错误号限-20000~-20999,消息≤2048字节,Java需配置oracle.jdbc.RetainV9Binding=true才能透传错误码。
ORA-20000 类错误怎么抛出才有效
直接用 raise_application_error 才能被客户端捕获为真正的异常,而不是静默失败或报 ora-06512。它不是普通函数,是 pl/sql 内置过程,必须在可执行块中调用,不能放在声明区或 sql 表达式里。
- 错误编号必须是 -20000 到 -20999 之间的整数,超出范围会报 ORA-21000
- 错误消息长度不能超过 2048 字节,超长部分会被截断且不报错
- 第三个参数
keep_error_stack设为TRUE时,能保留原始调用栈(Oracle 10gR2+),否则只显示当前行 - 不要在触发器里抛错后还试图 COMMIT —— 触发器属于事务上下文,抛错会导致整个事务回滚,再 COMMIT 会报 ORA-06519
PL/SQL 存储过程里怎么安全抛错
常见误区是把校验逻辑和 RAISE_APPLICATION_ERROR 写在同一个 IF 分支末尾却忘了加 RETURN 或 NULL,导致后续代码继续执行,可能引发数据不一致。
- 推荐写法:校验失败立刻抛错 + 显式
RETURN(如果是函数)或直接结束逻辑(过程) - 避免嵌套过深:用
IF NOT condition THEN RAISE_APPLICATION_ERROR(...); END IF;比多层 ELSE 更易读 - 如果需要记录日志再抛错,先调用
DBMS_OUTPUT.PUT_LINE或写入表,但注意生产环境通常禁用DBMS_OUTPUT - 示例:
IF p_amount < 0 THEN RAISE_APPLICATION_ERROR(-20001, '金额不能为负数'); RETURN; -- 函数中必须有 END IF;
Java 调用时为什么捕获不到自定义错误码
Oracle 默认把 RAISE_APPLICATION_ERROR 抛出的错误映射成 SQLException,但错误码变成 17001(内部错误)或 0,原始 -20001 丢失 —— 这是因为 JDBC 驱动没开启错误代码透传。
- 必须在连接 URL 加
oracle.jdbc.RetainV9Binding=true(12c 及以后建议用oracle.jdbc.fanEnabled=false配合设置) - Java 侧要用
SQLException.getErrorCode()获取,不是getSQLState() - Spring JDBC 中,
@Transactional方法内抛错会触发回滚,但若上层吞了异常没 re-throw,错误码就彻底不可见 - 调试时可在 SQL*Plus 里先执行对应过程,确认
SHOW ERRORS和实际报错一致
和标准异常 RAISE 的区别在哪
RAISE_APPLICATION_ERROR 是用户级错误,带编号和消息;而 RAISE 只能重抛当前异常或预定义异常(如 NO_DATA_FOUND),不能自定义编号。
- 不能用
RAISE -20001—— 语法错误,会报 PLS-00103 -
RAISE_APPLICATION_ERROR会立即终止当前 PL/SQL 块,而RAISE只能向上冒泡,未必中断执行 - 想统一处理多种错误?别堆砌多个
RAISE_APPLICATION_ERROR,改用异常声明 +RAISE+EXCEPTION块更可控 - 注意:
RAISE_APPLICATION_ERROR不会触发AFTER SERVERERROR触发器,它不算“服务器错误”
最常被忽略的是错误编号范围校验和 JDBC 连接参数 —— 很多人本地测试 OK,一上生产就发现 Java 拿不到码,其实只是驱动没配对。

















