如何在Java(Spring Boot)中捕获PostgreSQL存储过程抛出的错误
问题描述
我在PostgreSQL存储过程中编写了错误抛出逻辑,用于插入记录前检查组合是否已存在,错误抛出代码如下:
IF (var_RecordCount <> 0) THEN RAISE 'Error %, severity %, state % was raised. Message: %.', '50000', 5, 1, 'Selected combination is already present in Database...' USING ERRCODE = '50000'; ELSE --- DO Something Else END IF;
我用Java(Spring Boot)调用该存储过程的代码如下:
Connection conn = DatabaseConnection.connect(); PreparedStatement stmt = null; Boolean isSuccess = false; try { stmt = conn.prepareStatement("call public.my-sp(?,?,?,?,?,?);"); stmt.setInt(1, ""); // 注:此处代码存在错误,setInt不能传入空字符串,需传入合法整数 stmt.setString(2, ""); stmt.setString(3, ""); stmt.setString(4, ""); stmt.setString(5, ""); stmt.setString(6, ""); int status = stmt.executeUpdate(); isSuccess = (status == 0) || (status > 0); } catch (Exception e) { LOGGER.error("Error occurred during calling SP : my_sp().", e); } finally { try { stmt.close(); conn.close(); } catch (SQLException e) { LOGGER.error("Error in connection close.", e); } } return isSuccess;
我的问题是:如何在Java代码中捕获存储过程内部抛出的这个错误?有没有可行的实现方法?
解决方案
1. 捕获特定SQL错误码(推荐方案)
PostgreSQL抛出的错误会被JDBC封装为SQLException,你可以通过SQLException.getSQLState()获取存储过程中指定的错误码(即50000),从而针对性处理这个业务错误:
修改catch块逻辑:
catch (SQLException e) { // 匹配存储过程抛出的错误码 if ("50000".equals(e.getSQLState())) { // 处理重复记录的业务逻辑,比如返回提示或抛出自定义业务异常 LOGGER.error("记录组合已存在", e); isSuccess = false; } else { // 处理其他数据库异常 LOGGER.error("调用存储过程my_sp时发生未知数据库错误", e); isSuccess = false; } } catch (Exception e) { // 处理非数据库类型的异常 LOGGER.error("调用存储过程my_sp时发生错误", e); isSuccess = false; }
2. 优化存储过程的错误信息(可选)
可以简化存储过程的RAISE语句,让错误信息更直接,同时保留ERRCODE:
IF (var_RecordCount <> 0) THEN RAISE EXCEPTION 'Selected combination is already present in Database...' USING ERRCODE = '50000'; END IF;
这样Java端通过e.getMessage()就能直接获取业务提示,无需解析格式化字符串。
3. 修复Java代码中的明显错误
当前代码里的stmt.setInt(1, "");是非法调用,setInt方法必须传入整数类型参数,需修正为合法值,例如:
stmt.setInt(1, 0); // 或根据业务逻辑传入对应整数
4. 资源关闭优化(可选)
使用try-with-resources语法可以自动关闭Connection和PreparedStatement,避免手动关闭可能出现的遗漏:
Boolean isSuccess = false; try (Connection conn = DatabaseConnection.connect(); PreparedStatement stmt = conn.prepareStatement("call public.my_sp(?,?,?,?,?,?);")) { stmt.setInt(1, 0); stmt.setString(2, ""); stmt.setString(3, ""); stmt.setString(4, ""); stmt.setString(5, ""); stmt.setString(6, ""); int status = stmt.executeUpdate(); isSuccess = status >= 0; } catch (SQLException e) { if ("50000".equals(e.getSQLState())) { LOGGER.error("记录组合已存在", e); isSuccess = false; } else { LOGGER.error("数据库操作错误", e); isSuccess = false; } } catch (Exception e) { LOGGER.error("调用存储过程失败", e); isSuccess = false; } return isSuccess;
内容的提问来源于stack exchange,提问作者Som
相关产品推荐
相关产品推荐

