【问题标题】:Avoiding skipping a row By next() Method of ResultSet避免跳行通过 ResultSet 的 next() 方法
【发布时间】:2017-10-20 15:40:39
【问题描述】:

这是一个简单的代码打印数据库中的一些行。但是当我执行此操作时,屏幕上不会打印任何内容。我认为问题是rs.next() 方法正在跳过一行。那么如何避免这种情况或重置rs.next() 方法的位置?

 String searchword = Searchtf.getText();
 try {
        Class.forName("com.mysql.jdbc.Driver");

        java.sql.Connection con = DriverManager.getConnection(url, db_username, db_password);

        java.sql.Statement stat = con.createStatement();

        String searchQuery = "SELECT * FROM user WHERE Name LIKE '" + searchword + "' ";

java.sql.ResultSet rs = stat.executeQuery(searchQuery);

        if (rs.next()) {
            while (rs.next()) {
                System.out.print(rs.getString("idUser") + " ,");
                System.out.print(rs.getString("Name") + " ,");
                System.out.print(rs.getString("Email") + " ,");
                System.out.println(rs.getString("country") + " .");
            }
        } else {
            JOptionPane.showMessageDialog(null, "Not Found");
        }
  } catch (Exception ex) {
        ex.printStackTrace();
    }

【问题讨论】:

标签: java mysql database jdbc resultset


【解决方案1】:

The API docs for ResultSet 解释一下 next() 方法:

将光标从当前位置向前移动一行。一种 ResultSet 游标最初位于第一行之前;这 第一次调用 next 方法使第一行成为当前行;这 第二次调用使第二行成为当前行,依此类推。

每次调用 next() 方法时,都会将光标移动到下一行。 这发生在您的代码中(两次):

if (rs.next()) {
            while (rs.next()) { 

避免该问题的一种方法是使用方法 beforeFirst()。 According to the API:

将光标移动到此 ResultSet 对象的前面,就在前面 第一行。如果结果集不包含此方法,则此方法无效 行。

然后,每次您在代码中的某个位置使用“rs.next()”时,您都会将光标移动一个位置(到下一行),但如果在多次使用 rs.next() 之后,您需要从第一行你可以简单地使用 rs.beforeFirst() ,当你下次调用 rs.next() 时,光标将从结果集的开头开始。

您也不需要在代码中使用 if 语句:

if (rs.next()) {

因为你使用的时间就足够了。

【讨论】:

    【解决方案2】:

    不用不用:

     if (rs.next()) {
    

    while 就足够了,这使得结果两次。 相反,您可以使用:

    boolean b = false;
    while (rs.next()) {
       b = true;
       ...
    }
    
    if(!b) {
      JOptionPane.showMessageDialog(null, "Not Found");
    }
    

    您必须改用 PreparedStatement,以避免任何 SQL 注入或语法错误。

    【讨论】:

    • 如果没有if 语句,您将如何处理else?那里有一些选项(根据我的回答),但您不认为这是要在您的回答中处理的问题。
    • OP 可以在 while 内使用布尔值来知道是否有结果@JonSkeet
    • 对,所以请在答案中注明。我的观点是,正如您的回答所暗示的那样,他们不能只是删除if 声明。
    【解决方案3】:

    感谢您的每一个回答。我发现输入rs.relative(-1) 也可以完成这项工作。但是上面的答案编码很好,比我的要好。所以谢谢大家。我是编程新手,我会在编码中考虑您的所有建议。谢谢

    if (rs.next()) {
         rs.relative(-1);
            while (rs.next()) {
                System.out.print(rs.getString("idUser") + " ,");
                System.out.print(rs.getString("Name") + " ,");
                System.out.print(rs.getString("Email") + " ,");
                System.out.println(rs.getString("country") + " .");
            }
     }
    

    【讨论】:

    • relative(-1) 并不总是有效,例如它不适用于 TYPE_FORWARD_ONLY 结果集,这通常是默认值。
    【解决方案4】:

    首先,停止这样构建 SQL - 使用参数化 SQL 和 PreparedStatement。您当前的代码容易受到 SQL 注入攻击。

    基本上,不要连续调用两次rs.next()(首先在if 中,然后在while 中)...您可以通过将while 循环转换为do/while 轻松做到这一点循环:

    if (rs.next()) {
        do {
            System.out.print(rs.getString("idUser") + " ,");
            System.out.print(rs.getString("Name") + " ,");
            System.out.print(rs.getString("Email") + " ,");
            System.out.println(rs.getString("country") + " .");
        } while (rs.next());
    }
    

    或者只是while循环,带有一个单独的变量来检测你已经看到一些结果:

    bool anyResults = false;
    while (rs.next()) {
        anyResults = true;
        System.out.print(rs.getString("idUser") + " ,");
        System.out.print(rs.getString("Name") + " ,");
        System.out.print(rs.getString("Email") + " ,");
        System.out.println(rs.getString("country") + " .");
    }
    if (!anyResults) {
        JOptionPane.showMessageDialog(null, "Not Found");
    }
    

    (此外,您应该使用 try-with-resources 来关闭您的 ResultSet 等,并且仅将堆栈跟踪打印到 stdout 几乎从来都不是处理异常的适当方式...)

    【讨论】:

    • 感谢您的回答。好吧,我将在以后的代码中使用参数化 SQL 和 PreparedStatement。 rs.relative(-1) 也为我工作!我查过了
    • @Nazeer:不,修复你的当前代码。你有一个安全漏洞。说“我下次会做”是不够的。养成保护自己免受 SQL 注入攻击的习惯真的非常非常非常非常重要,现在是开始的最佳时机。
    • 嗯,谢谢.. 我对参数化 SQL 和 PreparedStatement 的了解并不多。我现在就去学。
    • @Nazeer:太好了——这正是我们应该采取的态度:)
    【解决方案5】:

    rs.next() 将增加 if 中的游标,因此如果结果集只有一行由查询返回,则 while 将再次移动游标,并且不会打印任何数据。请改用 do..while 循环。

    if (rs.next()) {
                do {
                    System.out.print(rs.getString("idUser") + " ,");
                    System.out.print(rs.getString("Name") + " ,");
                    System.out.print(rs.getString("Email") + " ,");
                    System.out.println(rs.getString("country") + " .");
                }while (rs.next());
            } 
    

    【讨论】:

      【解决方案6】:

      嘿,它正在跳过行,因为您在 if 子句中执行 rs.next(),然后在 while 中再次执行。所以第一次迭代实际上是第二行。最好的选择是在 if 子句中你应该写 if(rs.first())

      【讨论】:

      • 对于只转发的ResultSet 会失败,如果成功,它会仍然跳过第一行,因为对first() 的调用后面会跟一个致电next()。确保 next 只被调用正确的次数更简单 - 请参阅我的答案以获得两个选项。
      猜你喜欢
      • 1970-01-01
      • 2016-02-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-09
      • 2016-04-24
      相关资源
      最近更新 更多