9

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

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

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

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

  • getString(1)不适用于空(零行)结果集(根据设计或由于错误)
  • ResultSet的“打开”标志设置false为零行(再次,设计或错误)

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

我的问题是:

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

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

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

谢谢!

4

4 回答 4

18

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

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?
}
于 2009-11-29T02:26:05.387 回答
6
while (rs.next()) {
 // process the row
}
于 2009-11-28T21:49:10.883 回答
5

来自ResultSet的 JavaDocs :

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

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

于 2009-11-28T22:10:13.617 回答
1

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

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);
于 2015-05-07T12:37:26.913 回答