Java中应直接调用SQLException.getErrorCode()获取RAISE_APPLICATION_ERROR的错误码(如-20001→2001),需配置JDBC URL参数oracle.jdbc.RetainV9Binding=true,且catch必须包裹DML执行语句而非commit。
Java里怎么拿到RAISE_APPLICATION_ERROR的错误码
直接读 sqlexception.geterrorcode(),别碰 getmessage() 或 getsqlstate()。oracle jdbc 驱动把 raise_application_error(-20001, 'xxx') 映射成 sqlexception 后,geterrorcode() 返回的就是 20001(绝对值),不是 -20001,也不是 "20001" 字符串。
常见错误:
- 用
ex.getMessage().contains("ORA-20001")做判断 —— 消息可能被本地化、含换行、被截断 - 依赖
getSQLState(),它对所有自定义错误基本都是"72000",无法区分业务含义 - 检查
getCause()是否为SQLException—— 没必要,JDBC 已把异常扁平化,SQLException就是根异常
连接URL必须加oracle.jdbc.RetainV9Binding=true
不加这个参数,getErrorCode() 会返回 0 或 17001,原始错误码彻底丢失。这是 Oracle JDBC 驱动默认行为,不是 Java 层能绕过的。
配置方式:
- JDBC URL 示例:
jdbc:oracle:thin:@//host:1521/orcl?oracle.jdbc.RetainV9Binding=true - 如果是 HikariCP 等连接池,需在
dataSourceProperties中显式设置该 key-value - Oracle 12c+ 可考虑改用
oracle.jdbc.fanEnabled=false,但RetainV9Binding=true兼容性更稳
catch要套在executeUpdate()这一行,不是commit()外面
触发器异常在 DML 执行时就抛出,不是事务提交时。把 catch 放在 commit() 外面,等于没捕获。
立即学习“Java免费学习笔记(深入)”;
正确写法示例:
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
try {
stmt.executeUpdate("INSERT INTO account(id, balance) VALUES (1001, -100)");
} catch (SQLException ex) {
if (ex.getErrorCode() == 20001) {
// 处理余额不足
} else if (ex.getErrorCode() == 20002) {
// 处理超限
}
}
错误写法:
stmt.executeUpdate("INSERT ..."); // 异常在这里已抛出,但没被 catch
conn.commit(); // 这里根本走不到
Spring/JPA/MyBatis环境下要小心异常包装
这些框架默认把 SQLException 转成 unchecked 异常(如 DataAccessException),原始错误码会被吞掉。
应对方式:
- 用
getCause()往下挖一层,直到找到SQLException:if (e.getCause() instanceof SQLException) - 在 MyBatis 的
@Select/@Update方法上加throws SQLException,强制暴露底层异常 - Spring 中可配
@Transactional(rollbackFor = SQLException.class),但注意:仅控制回滚,不恢复错误码
最稳妥的做法,是在 DAO 层用原生 JDBC 或 JdbcTemplate.execute() 回调,自己处理 SQLException,避免框架二次封装。
真正容易被忽略的是驱动参数和异常捕获位置——错一个,getErrorCode() 就是废的。业务逻辑再严谨,也拦不住错误码传不进来。

















