JDBC 驱动程序在空 ResultSet 上抛出“ResultSet Closed”异常
Posted
技术标签:
【中文标题】JDBC 驱动程序在空 ResultSet 上抛出“ResultSet Closed”异常【英文标题】:JDBC driver throws "ResultSet Closed" exception on empty ResultSet 【发布时间】:2010-12-21 07:04:44 【问题描述】:我在 SQLite 的 JDBC 驱动程序中遇到问题。
我正在使用 SELECT 语句执行查询。
如果我得到一个空的 ResultSet
(0 行),那么我会在调用 getString(1)
时看到一个“Closed ResultSet”异常。
在没有太多 JDBC 经验的情况下,我的理论(我无法通过 ResultSet
的 JavaDocs 确认)是这样的
getString(1)
不适用于空(零行)结果集(根据设计或由于错误)
ResultSet
的“open”标志在零行上设置为 false
(同样,由于设计或错误)
我看到了这个bug report,但不确定它是否相关。
我的问题是:
-
上述理论正确吗?
这是一个错误吗?特征? (如果是这样,有人可以指出文档吗?)
它是特定于 SQLIte 的 JDBC 还是所有 JDBC 驱动程序中的通用
ResultSet
?
这样做的正确方法是什么??
对于#4,我的解决方案是在executeQuery()
之后使用isFirst()
调用来检查结果集中是否存在任何行。这是最佳实践方法吗?
(我也可以简单地选择一个计数 insetad,因为我真的不需要结果集,只需要零非零标志,但如果我确实关心 select 的结果,我想知道正确的做法)
谢谢!
【问题讨论】:
谢谢大家!非常有启发性! 【参考方案1】:while (rs.next())
// process the row
【讨论】:
这回答了#4。 #1-3 怎么样? :)【参考方案2】:来自ResultSet 的 JavaDocs:
ResultSet 对象维护一个游标 指向其当前的数据行。 最初定位光标 在第一行之前。下一个方法 将光标移动到下一行,并且 因为它在那里返回false ResultSet 中不再有行 对象,它可以在while循环中使用 遍历结果集。
您需要将ResultSet
定位在一行中,例如在尝试读取任何数据之前调用next()
。如果对next()
的调用返回false
,则结果集为空。
【讨论】:
这回答了#4。 #1-3 怎么样? :) @DVK 在ResultSet
位于一行之前,调用getString
是没有意义的,因此引发异常是有意义的(这适用于任何JDBC 驱动程序) .我不确定“结果集的“打开”标志”指的是什么。
在 Eclipse 的调试器中,当检查结果集时,“open”成员的值为“false”。这就是“ResultSet closed”异常的原因(不是根本原因,而是在 JDBC 源代码中检查生成异常的直接变量)【参考方案3】:
是否为空,但执行以下操作总是错误:
resultSet = statement.executeQuery(sql);
string = resultSet.getString(1); // Epic fail. The cursor isn't set yet.
这不是错误。这是documented behaviour。每个decent JDBC tutorial 都会提到它。您需要使用next()
设置ResultSet 的光标,然后才能访问任何数据。
如果您真的对所谓的唯一行是否存在感兴趣,那么只需检查next()
的结果。例如在一个虚构的UserDAO
类中:
public boolean exist(String username, String password) throws SQLException
boolean exist = false;
try (
Connection connection = database.getConnection();
PreparedStatement statement = connection.prepareStatement("SELECT id FROM user WHERE username = ? AND password = MD5(?)");
)
statement.setString(1, username);
statement.setString(2, password);
try (ResultSet resultSet = statement.executeQuery())
exist = resultSet.next();
return exist;
如果您实际上只期望 零 或 一个 行,那么只需执行以下操作:
public User find(String username, String password) throws SQLException
User user = null;
try (
Connection connection = database.getConnection();
PreparedStatement statement = connection.prepareStatement("SELECT id, username, email, birthdate FROM user WHERE username = ? AND password = MD5(?)");
)
statement.setString(1, username);
statement.setString(2, password);
try (resultSet = statement.executeQuery())
if (resultSet.next())
user = new User(
resultSet.getLong("id"),
resultSet.getString("username"),
resultSet.getString("email"),
resultSet.getDate("birthdate"));
return user;
然后在业务/域对象中相应地处理它,例如
User user = userDAO.find(username, password);
if (user != null)
// Login?
else
// Show error?
如果您实际上只期望 零 或 许多 行,那么只需执行以下操作:
public List<User> list() throws SQLException
List<User> users = new ArrayList<User>();
try (
Connection connection = database.getConnection();
PreparedStatement statement = connection.prepareStatement("SELECT id, username, email, birthdate FROM user");
ResultSet resultSet = statement.executeQuery();
)
while (resultSet.next())
users.add(new User(
resultSet.getLong("id"),
resultSet.getString("username"),
resultSet.getString("email"),
resultSet.getDate("birthdate")));
return users;
然后在业务/域对象中相应地处理它,例如
List<User> users = userDAO.list();
if (!users.isEmpty())
int count = users.size();
// ...
else
// Help, no users?
【讨论】:
由于代码示例和文档链接的广泛性,我选择“接受”这个。【参考方案4】:对于这样的问题,你可能会这样使用
while(rs.next())
String name=rs.getString("Name");
int roll_no=Integer.parseInt(rs.getString("Roll"));
finally
try
rs.close();
pst.close();
catch(Exception ee)
Joptionpane.showmessahedialog(this,ee);
【讨论】:
注意格式化帖子。我已经格式化了您的一个答案,请检查并格式化其他答案(如果有)! thanx Paresh Mayani 我是这个网站的新手。 不用担心...继续贡献!以上是关于JDBC 驱动程序在空 ResultSet 上抛出“ResultSet Closed”异常的主要内容,如果未能解决你的问题,请参考以下文章
尝试使用 H2 数据库更新 JDBC ResultSet 时出现异常
django makemigration 在子应用程序上抛出错误
glCreateShader 在 OSX 上抛出异常,为啥?