一尘不染

JDBC驱动程序在空的ResultSet上引发“ ResultSet Closed”异常

java

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

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

如果我得到一个空ResultSet(0行),则在调用时会抛出“ Closed ResultSet”异常getString(1)

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

  • getString(1) 对空(零行)结果集不起作用(通过设计或由于错误)
  • ResultSet的“打开”标志设置false为零行(同样是设计或错误)

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

我的要求是:

  1. 以上理论正确吗?
  2. 是虫子吗?特征?(如果是这样,有人可以指向文档吗?)
  3. 它是特定于SQLIte的JDBC还是ResultSet所有JDBC驱动程序中的泛型?
  4. 做这样的事情的正确方法是什么?

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

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

谢谢!


阅读 192

收藏
2020-09-08

共1个答案

一尘不染

是否为空,但执行以下操作始终会 出错

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

这不是错误。这是记录的行为。每个不错的JDBC教程都提到了它。您需要先使用设置ResultSet的游标,next()然后才能访问任何数据。

如果您实际上对所谓的唯一行是否 存在 感兴趣,则只需检查的结果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?
}
2020-09-08