编译错误应先用 SHOW ERRORS PROCEDURE your_procedure_name 查看,它能精准返回行号、列号及错误描述;运行时错误则必须在 EXCEPTION 块首行调用 DBMS_UTILITY.FORMAT_ERROR_BACKTRACE 获取真实出错位置和调用链。

直接查编译错误:用 SHOW ERRORS 最快
存储过程创建或重编译失败时,Oracle 不会自动打印详细错误,只返回类似 PL/SQL: ORA-00904: "XXX" invalid identifier 这种模糊提示。此时别急着翻代码,先在 SQL*Plus 或 SQL Developer 的命令行里执行:SHOW ERRORS PROCEDURE your_procedure_name(注意名称必须全大写,如 P_INSERT_USER)。
它会列出所有编译错误,包括行号、列号和具体描述。常见坑是:名字写小写、拼错、漏掉 PROCEDURE 关键字,导致返回 “no errors”——其实根本没查对对象。
运行时报错看不到堆栈?必须用 DBMS_UTILITY.FORMAT_ERROR_BACKTRACE
仅靠 SQLERRM 只能拿到 ORA-06502: PL/SQL: numeric or value error 这类泛泛而谈的信息,完全不知道错在哪一行、哪个嵌套过程里。
真正有用的堆栈必须在异常处理块中第一行调用:DBMS_UTILITY.FORMAT_ERROR_BACKTRACE,例如:
EXCEPTION
WHEN OTHERS THEN
-- 必须放第一行!
v_backtrace := DBMS_UTILITY.FORMAT_ERROR_BACKTRACE;
v_errmsg := SQLERRM || CHR(10) || v_backtrace;
INSERT INTO error_log VALUES (v_errmsg, SYSDATE);
COMMIT;
RAISE; -- 或 RAISE_APPLICATION_ERROR(-20001, v_errmsg, TRUE);
END;关键点:
• 不能在 RAISE 前做任何变量赋值或日志写入,否则堆栈被截断
• FORMAT_ERROR_BACKTRACE 和 FORMAT_ERROR_STACK 完全不同:后者只返回错误码+消息,前者才带完整调用链(如 ORA-06512: at "SCOTT.PKG_DATA.PROC_LOAD", line 87)
• Oracle 12c+ 可配合 UTL_CALL_STACK 获取结构化信息,但不能替代 FORMAT_ERROR_BACKTRACE 定位原始错误点
Spring Boot 调用时堆栈丢失?JDBC 驱动默认只暴露表层异常
Java 应用里捕获到的 SQLException,e.getMessage() 往往只剩 ORA-06550 和参数类型不匹配这类笼统提示,PL/SQL 内部的行号、调用链全丢了。
解决办法不是改 Java 逻辑,而是确保 PL/SQL 层已把完整上下文写进日志或表里:
• 存储过程中必须用 DBMS_UTILITY.FORMAT_ERROR_BACKTRACE 记录并返回(或插入日志表)
• Java 层不要只打 e.getMessage(),而要记录 e.getErrorCode()、e.getSQLState() 和完整堆栈:log.error("Failed to call {}", procName, e)
• 如果用 MyBatis 或 JdbcTemplate,确保未开启 spring.datasource.hikari.leak-detection-threshold 等干扰项,避免连接提前关闭导致异常被吞
调试阶段别依赖 DBMS_OUTPUT.PUT_LINE
很多人习惯在关键位置加 DBMS_OUTPUT.PUT_LINE('step 1') 来“猜”执行路径,但这有严重局限:
• 输出默认被缓冲,异常退出时可能根本没刷出
• 生产环境通常禁用 DBMS_OUTPUT,测试有效不代表上线有效
• 无法看到变量真实值(比如 NULL vs 空字符串)
真正可靠的手段是:
• 在 PL/SQL Developer 或 SQL Developer 中用图形化调试器单步执行,实时看变量窗口
• 把关键变量拼进日志表(如 INSERT INTO debug_log VALUES ('before_update', v_id, SYSDATE))
• 对复杂逻辑,优先用 UTL_CALL_STACK 打印当前调用栈,确认是否进了预期分支
Oracle 的错误信息分两层:编译期错误靠 SHOW ERRORS 查,运行期错误靠 DBMS_UTILITY.FORMAT_ERROR_BACKTRACE 拿真实堆栈。这两者不结合,等于只看半张病历就开药。


















