PostgreSQL无返回值存储过程Java调用的执行结果判断问题
PostgreSQL存储过程Java调用的执行状态判断问题
我在PostgreSQL数据库中有一个用于保存/更新系统用户特定数据的存储过程(SP),调用时无返回值。现在想从Java中调用这个存储过程,但不知道怎么判断执行成功还是失败。
我的代码如下:
Connection conn = DatabaseConnection.connect(); PreparedStatement stmt = conn.prepareStatement("call public.spsaveuser (?,?,?,?,?);"); // CallableStatement stmt = conn.prepareCall("{CALL public.spsaveuser (?,?,?,?,?) }"); stmt.setString(1, userName); stmt.setString(2, someString); stmt.setString(3, anotheString); stmt.setBoolean(4, someBoolean); stmt.setInt(5, someIntegerVal); int numColsAffected = stmt.executeUpdate(); System.out.println("numColsAffected : " + numColsAffected); return (numColsAffected > 0);
我发现numColsAffected始终返回0,但数据库里的表确实已经被更新了。这种情况下,我该通过什么返回值来确认执行的成功或失败?
更新
SQL Server的存储过程默认会返回一个整数表示执行状态:0代表成功,非零代表错误。但PostgreSQL的官方文档里并没有提到这类明确的返回值。
解决方案
- 通过异常捕获判断执行失败
PostgreSQL的JDBC驱动在存储过程执行出错时(比如语法错误、约束违反、权限不足等)会直接抛出SQLException。因此可以通过捕获该异常判断执行失败,没有抛出异常则说明执行成功。
修改后的代码示例:
try (Connection conn = DatabaseConnection.connect(); PreparedStatement stmt = conn.prepareStatement("call public.spsaveuser (?,?,?,?,?);")) { stmt.setString(1, userName); stmt.setString(2, someString); stmt.setString(3, anotheString); stmt.setBoolean(4, someBoolean); stmt.setInt(5, someIntegerVal); stmt.executeUpdate(); // 未抛出异常即执行成功 return true; } catch (SQLException e) { // 执行失败,可在此处理日志或错误逻辑 e.printStackTrace(); return false; }
注意使用try-with-resources语法自动关闭连接和Statement,避免资源泄漏。
- 修改存储过程,返回自定义状态或受影响行数
如果需要明确知道是否有数据被修改,可以修改PostgreSQL存储过程,让它返回受影响行数或自定义状态标识:
CREATE OR REPLACE PROCEDURE public.spsaveuser( p_username text, p_somestring text, p_anotherstring text, p_someboolean boolean, p_someinteger integer, OUT p_affected_rows integer) LANGUAGE plpgsql AS $$ BEGIN -- 原有更新/保存逻辑 UPDATE your_table SET ... WHERE username = p_username; -- 获取受影响行数 GET DIAGNOSTICS p_affected_rows = ROW_COUNT; END; $$;
之后在Java中使用CallableStatement调用并获取输出参数:
try (Connection conn = DatabaseConnection.connect(); CallableStatement stmt = conn.prepareCall("{CALL public.spsaveuser (?,?,?,?,?,?)}")) { stmt.setString(1, userName); stmt.setString(2, someString); stmt.setString(3, anotheString); stmt.setBoolean(4, someBoolean); stmt.setInt(5, someIntegerVal); // 注册输出参数类型 stmt.registerOutParameter(6, Types.INTEGER); stmt.execute(); // 获取受影响行数 int affectedRows = stmt.getInt(6); return affectedRows > 0; } catch (SQLException e) { e.printStackTrace(); return false; }
- 使用
execute()配合getUpdateCount()获取更新计数
如果不想修改存储过程,也可以用execute()方法执行,再通过getUpdateCount()获取实际受影响行数:
try (Connection conn = DatabaseConnection.connect(); PreparedStatement stmt = conn.prepareStatement("call public.spsaveuser (?,?,?,?,?);")) { stmt.setString(1, userName); stmt.setString(2, someString); stmt.setString(3, anotheString); stmt.setBoolean(4, someBoolean); stmt.setInt(5, someIntegerVal); boolean hasResultSet = stmt.execute(); int updateCount = stmt.getUpdateCount(); // 处理可能存在的结果集和更新计数 while (hasResultSet || updateCount != -1) { if (!hasResultSet) { System.out.println("受影响行数: " + updateCount); } hasResultSet = stmt.getMoreResults(); updateCount = stmt.getUpdateCount(); } return true; } catch (SQLException e) { e.printStackTrace(); return false; }
内容的提问来源于stack exchange,提问作者Som
相关产品推荐
相关产品推荐

