java JDBC 驱动程序在空 ResultSet 上抛出“ResultSet Closed”异常

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1813858/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 18:06:02  来源:igfitidea点击:

JDBC driver throws "ResultSet Closed" exception on empty ResultSet

javasqliteexceptionjdbcresultset

提问by DVK

I have a problem in JDBC driver for SQLite.

我在 SQLite 的 JDBC 驱动程序中遇到问题。

I am executing a query with SELECT statement.

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

If I get an empty ResultSet(0 rows) then I see a "Closed ResultSet" exception thrown when calling getString(1).

如果我得到一个空ResultSet(0 行),那么我会在调用getString(1).

Without much prior JDBC experience, my theory (which I could not confirm via JavaDocs for ResultSet) is that

没有太多的 JDBC 经验,我的理论(我无法通过 JavaDocs for 确认ResultSet)是

  • getString(1)does NOT work on an empty (zero-row) resultset (by design or due to a bug)
  • ResultSet's "open" flag is set to falseon zero rows (again, by design or a bug)
  • getString(1)不适用于空(零行)结果集(通过设计或由于错误)
  • ResultSet的“打开”标志设置false为零行(再次,设计或错误)

I saw this bug reportbut am not sure if it's related.

我看到了这个错误报告,但不确定它是否相关。

My qeustions are:

我的问题是:

  1. Is the theory above correct?
  2. Is it a bug? Feature? (and if so, can someone point to documentation please?)
  3. Is it specific to SQLIte's JDBC or to generic ResultSetin all JDBC drivers?
  4. What is the correct way of doing stuff like that??
  1. 上面的理论对吗?
  2. 这是一个错误吗?特征?(如果是这样,有人可以指出文档吗?)
  3. 它是特定于 SQLIte 的 JDBC 还是ResultSet所有 JDBC 驱动程序中的通用?
  4. 做这样的事情的正确方法是什么??

For #4, my solution was to use isFirst()call right after executeQuery()to check whether any rows are there in result set. Is this the best practice approach?

对于#4,我的解决方案是使用isFirst()call right afterexecuteQuery()检查结果集中是否有任何行。这是最佳实践方法吗?

(I could also have simply selected a count insetad since I didn't really need a result set, merely zero-nonzero flag, but I want to know the correct thingh to do if I did care about select's results)

(我也可以简单地选择一个计数 insetad,因为我真的不需要结果集,只是零非零标志,但我想知道如果我确实关心选择的结果,正确的做法是什么)

Thanks!

谢谢!

回答by BalusC

Empty or not, but doing the following is always faulty:

是否为空,但执行以下操作总是错误的

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

This is not a bug. This is documented behaviour. Every decent JDBC tutorialmentions it. You need to set the ResultSet's cursor using next()before being able to access any data.

这不是错误。这是记录在案的行为。每个体面的 JDBC 教程都提到了它。next()在能够访问任何数据之前,您需要使用设置 ResultSet 的游标。

If you're actually interested whether the supposedly unique row existor not, then just check the outcome of next(). For example in a fictive UserDAOclass:

如果您真的对所谓的唯一行是否存在感兴趣,那么只需检查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;
}

If you actually expect only zeroor onerow, then just do something like:

如果你真的希望只有一个行,那么就这样做:

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

and then just handle it accordingly in the business/domain object, e.g.

然后在业务/域对象中相应地处理它,例如

User user = userDAO.find(username, password);

if (user != null) {
    // Login?
}
else {
    // Show error?
}

If you actually expect only zeroor manyrows, then just do something like:

如果你真的希望只有许多行,那么就这样做:

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

and then just handle it accordingly in the business/domain object, e.g.

然后在业务/域对象中相应地处理它,例如

List<User> users = userDAO.list();

if (!users.isEmpty()) {
    int count = users.size();
    // ...
}
else {
    // Help, no users?
}

回答by Doug Currie

while (rs.next()) {
 // process the row
}

回答by Phil Ross

From the JavaDocs for ResultSet:

来自ResultSet的 JavaDocs :

A ResultSet object maintains a cursor pointing to its current row of data. Initially the cursor is positioned before the first row. The next method moves the cursor to the next row, and because it returns false when there are no more rows in the ResultSet object, it can be used in a while loop to iterate through the result set.

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

You'll need to position the ResultSeton a row, e.g. by calling calling next(), before attempting to read any data. If the call to next()returns falsethen the result set is empty.

在尝试读取任何数据之前ResultSet,您需要将 定位在一行上,例如通过调用调用next()。如果调用next()返回,false则结果集为空。

回答by manikant gautam

For such kind of of problem you might use like that

对于此类问题,您可能会像那样使用

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