英文:
ResultSet.isBeforeFirst throws NullPointerException unexpectedly
问题
private ResultSet getResultSet(String id) {
RDSPooledConnector rdsPooledConnector = connector.getConnector(endpoint, port);
try (Connection connection = rdsPooledConnector.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement(query)) {
preparedStatement.setString(1, id);
return preparedStatement.executeQuery();
} catch (SQLException exception) {
LOGGER.error("无法检索结果集 {}", id, exception);
return null;
}
}
@Override
public boolean shouldMove(String id) {
try {
ResultSet resultSet = getResultSet(id);
return resultSet != null && resultSet.isBeforeFirst(); // 此行!
} catch (SQLException exception) {
LOGGER.error("失败: {}", id, exception);
return false;
}
}
堆栈跟踪为:
java.lang.NullPointerException: 空值
at com.mysql.jdbc.ResultSetImpl.isBeforeFirst(ResultSetImpl.java:6104)
at com.zaxxer.hikari.pool.HikariProxyResultSet.isBeforeFirst(HikariProxyResultSet.java)
我在抛出 NPE 的那一行加了注释。我想知道为什么会出现这种情况,考虑到 ResultSet
在 getResultSet
方法的 try
块之后被访问。因此,我假设当到达调用 isBeforeFirst
的那行代码时,连接已关闭,即使多个线程调用此方法,每个线程都会有自己的连接。
下面是 ResultSetImpl.java
中的 isBeforeFirst
方法的代码:
public boolean isBeforeFirst() throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
return this.rowData.isBeforeFirst();
}
}
显然,rowData
为 null。但我不明白为什么会出现这种情况。
<details>
<summary>英文:</summary>
I have the following code:
private ResultSet getResultSet(String id) {
RDSPooledConnector rdsPooledConnector = connector.getConnector(endpoint, port);
try (Connection connection = rdsPooledConnector.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement(query)) {
preparedStatement.setString(1, id);
return preparedStatement.executeQuery();
} catch (SQLException exception) {
LOGGER.error("Failed to retrieve result set {}", id, exception);
return null;
}
}
@Override
public boolean shouldMove(String id) {
try {
ResultSet resultSet = getResultSet(id);
return resultSet != null && resultSet.isBeforeFirst(); // THIS LINE!
} catch (SQLException exception) {
LOGGER.error("Failed: {}", id, exception);
return false;
}
}
I commented on the line that throws NPE. The stack trace is:
java.lang.NullPointerException: null
at com.mysql.jdbc.ResultSetImpl.isBeforeFirst(ResultSetImpl.java:6104)
at com.zaxxer.hikari.pool.HikariProxyResultSet.isBeforeFirst(HikariProxyResultSet.java)
I'm wondering why this could happen, considering that the `ResultSet` is being accessed after the `try` block in `getResultSet` method. So I assume the connection is closed when it gets to the line where `isBeforeFirst` is called, and even if multiple threads call this method, each will have its own connection.
This is the code for `ResultSetImpl.java`'s `isBeforeFirst`:
public boolean isBeforeFirst() throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
return this.rowData.isBeforeFirst();
}
}
Apparently `rowData` is null. But I don't understand why.
</details>
# 答案1
**得分**: 2
`ResultSet`对象实际上不应在方法之间传递。@dan1st的评论正中要害。在`getResultSet()`方法中,您关闭了`PreparedStatement`,因此也关闭了`ResultSet`。如果您真的想在方法之间传递结果集,请考虑使用[javax.sql.CachedRowSet][1]。
<details>
<summary>英文:</summary>
`ResultSet` objects should not really be passed between methods. The comment by @dan1st hit the nail on the head. In method `getResultSet()` you close the `PreparedStatement` and therefore you close the `ResultSet`. If you really want to pass a result set between methods, consider [javax.sql.CachedRowSet][1]
[1]: https://docs.oracle.com/javase/8/docs/api/javax/sql/rowset/CachedRowSet.html
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论