【问题标题】:ResultSet reset when using recursion使用递归时重置结果集
【发布时间】:2012-03-21 07:26:52
【问题描述】:

我对 Java 中的 ResultSet 对象和递归有疑问。

我正在为大学编写一些代码,每当我找到一个后代时,我都会使用那个新节点进行递归,但是当我退出递归并尝试 rs.next() 时,指针已经从指向第 1 行返回到第 0 行,当它到达第 0 行时,rs.next() 失败并返回!我知道里面有一件事还没有读到!这是什么原因造成的?

我解决这个问题的唯一方法是遍历结果集并获取每个元素并将其添加到数组列表中,然后循环遍历数组列表,对数组中的每个元素进行递归!当然,这一定是解决这个问题的更好方法吗?

这是我正在使用的新代码

private Vector<String> getDescendents(String dogname, Vector<String> anc) {
    if (anc == null) anc = new Vector<String>();
    ArrayList<String> tempList = new ArrayList<String>(2);
    try {
        System.out.println("Inside ");
        childStmt.setString(1,dogname);
        childStmt.setString(2,dogname);
        ResultSet rs = childStmt.executeQuery();
        System.out.println("Before while "+rs.getRow());
        while (rs.next()){
            String col1 = rs.getString(1);
            tempList.add(col1);
            anc.add(col1);
        } 
        for (String s:tempList){
            getDescendents(s,anc);
        }

    }
    catch(Exception e) {
        doError(e, "Failed to execute ancestor query in getBreeding");
    }
    return anc;
}

然而在此之前,我在while 循环中调用了getDescendents,因此没有for 循环,也没有arraylist,但是当它实际递归时,当它退出递归时,它会丢失对结果集的跟踪。

更多细节: 当我使用调试器(几乎说 gdb 那里有太多 C)时,结果集的 ID 是相同的,但行指针已返回 0 并且 rs.next 调用失败!

再次感谢任何解释!

p.s 以前的样子

private Vector<String> getDescendents(String dogname, Vector<String> anc) {
    if (anc == null) anc = new Vector<String>();
    ArrayList<String> tempList = new ArrayList<String>(2);
    try {
        System.out.println("Inside ");
        childStmt.setString(1,dogname);
        childStmt.setString(2,dogname);
        ResultSet rs = childStmt.executeQuery();
        System.out.println("Before while "+rs.getRow());
        while (rs.next()){
            String col1 = rs.getString(1);
            anc.add(col1);
            getDescendendts(col1,anc);
        } 

    }
    catch(Exception e) {
        doError(e, "Failed to execute ancestor query in getBreeding");
    }
    return anc;
}

【问题讨论】:

  • 前面的代码是什么样子的?
  • Java 中的递归通常是一个坏主意,因为没有尾调用优化。在打开结果集的中间进行递归是一个糟糕的主意。
  • 是的,我同意我讨厌递归,但任务需要它:P 它适用于诸如遍历后代等的树遍历之类的事情,@nicholas.hauschild 在底部对其进行了编辑

标签: java sql recursion resultset


【解决方案1】:

您似乎在重复使用childStmt;不要这样做。来自Statement javadoc

默认情况下,每个 Statement 对象只能打开一个 ResultSet 对象 同时。因此,如果读取一个 ResultSet 对象是 与另一个阅读交错,每个必须已经生成 通过不同的 Statement 对象。 Statement中的所有执行方法 接口隐式关闭语句的当前 ResultSet 对象,如果 打开一个存在。

您必须先保存所有行,然后执行递归查询,或者为要获取的每个 ResultSet 创建一个新的 Statement

【讨论】:

  • 那是因为当我执行一个语句时它类似于打开一个到数据库的新连接所以当我再次调用 childstmt 时它会重新打开连接并且我失去了前一个语句的内容?天哪,阅读 javadoc 使递归听起来像一个糟糕的主意!谢谢,非常感谢!
  • 这可能是由于设计决定使Statement 保持简单。每个 Statement 处理多个 ResultSets 会带来更多复杂性,因此他们假设如果您要重用一个语句,那么您已经完成了以前的数据。在非递归情况下,这可能是正确的。
  • 此外,在进行递归数据库查找时,您应该:使用内置递归查询(oracle 的 CONNECT BY;postgres 的 WITH RECURSIVE)或批量获取层次结构的每个级别(即首先0 级别的节点,然后是 1 级别的所有节点)并将它们加入内存;数百次访问数据库变得非常缓慢。
  • @beerbajay 是的,看起来很明智,我可能会修改现有代码,以便可以创建一个新的 childstmt 而不是重用相同的。谢谢,一个非常快速的响应和最有帮助的社区!非常感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-09
  • 2021-12-24
  • 2017-09-11
  • 2011-06-18
  • 1970-01-01
  • 2014-06-24
相关资源
最近更新 更多