JDBC驱动程序在空的ResultSet上抛出“ResultSet Closed”exception

我在SQLite的JDBC驱动程序有问题。

我正在用SELECT语句执行查询。

如果我得到一个空的ResultSet (0行),那么当调用getString(1)时,会看到一个“Closed ResultSet”exception。

没有很多以前的JDBC经验,我的理论(我无法通过JavaDocs确认ResultSet )是这样的

  • getString(1)不能在空的(零行)结果集上工作(按照devise或由于错误)
  • ResultSet的“打开”标志在零行上设置为false (同样,按devise或错误)

我看到这个错误报告,但不知道是否相关。

我的问题是:

  1. 上面的理论是正确的吗?
  2. 这是一个错误? 特征? (如果是的话,有人可以指出文件吗?)
  3. 在所有JDBC驱动程序中,它是特定于SQLIte的JDBC还是genericsResultSet
  4. 做这样的事情的正确方法是什么?

对于#4,我的解决scheme是在executeQuery()之后使用isFirst() executeQuery()来检查结果集中是否有任何行。 这是最好的做法吗?

(我也可以简单地select一个计数插入因为我不需要一个结果集,只是零非零的标志,但如果我真的关心select的结果,我想知道正确的事情)

谢谢!

空或不空,但做以下总是有缺陷的

 resultSet = statement.executeQuery(sql); string = resultSet.getString(1); // Epic fail. The cursor isn't set yet. 

这不是一个错误。 这是logging的行为 。 每个体面的JDBC教程都提到它。 您需要使用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? } 
 while (rs.next()) { // process the row } 

从ResultSet的JavaDocs:

ResultSet对象维护一个指向其当前数据行的游标。 最初光标位于第一行之前。 下一个方法将光标移动到下一行,并且在ResultSet对象中没有更多行时返回false,它可以在while循环中用于遍历结果集。

在尝试读取任何数据之前,您需要将ResultSet放在一行上,例如调用next() 。 如果对next()的调用返回false那么结果集是空的。

对于这样的问题,你可能会这样使用

 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);