You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 03:25:35