Java执行PostgreSQL Upsert操作无法获取返回值的问题求助
Hey there, I see you're stuck trying to get the return value from a PostgreSQL Upsert (INSERT ... ON CONFLICT ... DO UPDATE) statement with a RETURNING clause in your Java code—even though it works perfectly fine in pgAdmin. Let's break down what's going wrong and how to fix it.
Why Your Attempts Failed
Let's go through each of your options to understand the root issues:
- Option 1: Using
executeUpdate()followed bygetResultSet()should theoretically work for statements withRETURNING, but theNullPointerExceptionsuggests either your driver version is too old to handle this flow correctly, or you didn't properly validate the result set's existence before accessing it. - Option 2: Using
executeQuery()for an Upsert is incorrect.executeQuery()is designed exclusively forSELECTqueries. DML statements like Upsert return an update count by default (even withRETURNING), so this will throw theNo results were returned by the queryerror every time. - Option 3: When
execute()returnedhasResult: false, it means your JDBC driver didn't recognize that theRETURNINGclause would produce a result set. This is almost certainly due to outdated dependencies—yourpostgresqldriver (42.2.12) and Google Cloud SQL socket factory (1.0.15) are both several years old and lack improvements for handlingRETURNINGin Upserts.
Step-by-Step Solutions
1. Update Your Dependencies
First, upgrade to newer, stable versions of the PostgreSQL JDBC driver and Cloud SQL socket factory. This will resolve most compatibility issues:
<!-- PostgreSQL JDBC Driver (latest stable as of 2024) --> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <version>42.6.0</version> </dependency> <!-- Google Cloud SQL Postgres Socket Factory --> <dependency> <groupId>com.google.cloud.sql</groupId> <artifactId>postgres-socket-factory</artifactId> <version>1.11.0</version> </dependency>
2. Correct JDBC Code Implementation
Use execute() to run your Upsert statement, then check if a result set is available (which it should be, thanks to the RETURNING clause). We'll use try-with-resources to auto-close the ResultSet and avoid resource leaks:
// Assume pstmt is a properly initialized PreparedStatement with all parameters set boolean hasResultSet = pstmt.execute(); boolean updated = false; if (hasResultSet) { try (ResultSet rs = pstmt.getResultSet()) { if (rs.next()) { // Using the column name is more readable than index updated = rs.getBoolean("Updated"); } } catch (SQLException e) { logger.error("Failed to retrieve RETURNING clause result", e); // Handle exception appropriately (rethrow, log, etc.) } } // Optional: Get the number of rows affected by the Upsert int affectedRows = pstmt.getUpdateCount(); logger.info("Affected rows: {}, Updated value: {}", affectedRows, updated);
3. Quick Checks to Rule Out Other Issues
- Double-check that all parameters in your
PreparedStatementare correctly set (no missing values or type mismatches). - Confirm that the case of your column names (like
"Updated") matches exactly what's in your PostgreSQL table—PostgreSQL is case-sensitive for quoted column names, which you're already handling correctly in your SQL. - If the problem persists after upgrading dependencies, test your code with a direct connection to a local PostgreSQL instance (bypassing the Cloud SQL socket factory) to rule out any issues with the socket factory itself.
内容的提问来源于stack exchange,提问作者IoT user

