存储在hashMap中的结果集给出零行计数

时间:2015-06-21 13:26:26

标签: java sql jdbc resultset

我的类中有两个方法,首先我调用方法dbExecuteStatement(),它执行sql查询。执行sql查询后,我得到一个ResultSet对象。我将此ResultSet对象保存在静态hashMap中,以便在我的下一个方法调用fetchResults()时,我可以使用现有结果集来检索结果。在地图中保存ResultSet对象的原因是,在fetchResults()方法请求参数中,我将获得最大获取行大小,并且基于该值,我将迭代结果集。这两种方法都应该从客户端称为个体。

现在我遇到的问题是,当我在fetchResults()方法中迭代ResultSet对象时,我得到的行数为零。如果我从dbExecuteStatement()中的hashMap获取相同的ResultSet,我得到实际的行数,即在我的情况下为5。我检查了我在fetchResults()方法和dbExecuteStatement()中放入哈希映射的ResultSet对象,它是同一个对象。但是,如果使用ResultSetMetaData方法和fetchResults()获取dbExecuteStatement()对象,则它们会有所不同。有人可以帮助我理解原因,为什么我得到的结果数为零。

以下是代码:

  public class HiveDao1 {
    private static Map<Object,Map<Object,Object>> databaseConnectionDetails 
        = new HashMap<Object,Map<Object,Object>>();

    //This method will execute the sql query and will save the ResultSet obj in a hashmap for later use
     public void dbExecuteStatement(DbExecuteStatementReq dbExecuteStatementReq){
      //I already have a connection object saved in map
      String uniqueIdForConnectionObject = dbExecuteStatementReq.getDbUniqueConnectionHandlerId();
      Map<Object,Object> dbObject = databaseConnectionDetails.get(uniqueIdForConnectionObject);
      Connection connection = (Connection) dbObject.get(DatabaseConstants.CONNECTION);

      try {

    Statement stmt = connection.createStatement() ;
        // Execute the query
    ResultSet resultSet = stmt.executeQuery(dbExecuteStatementReq.getStatement().trim()) ;

    //save the result set for further use, Result set will be used in fetchResult() call
    dbObject.put(DatabaseConstants.RESULTSET, resultSet);

    /*
     * Now below is the debugging code,which I put to compare the result set
     *  iteration dbExecuteStatement() and fetchResults method
     */
    ResultSet rs = (ResultSet) dbObject.get(DatabaseConstants.RESULTSET);

    ResultSetMetaData md = (ResultSetMetaData) dbObject.get(DatabaseConstants.RESULTSETMETADATA);

     System.out.println("==ResultSet fethced in dbExecuteStatement=="+rs);
     System.out.println("==ResultSet metadata fetched in dbExecuteStatement ==="+rs.getMetaData());

    int count = 0;
    while (rs.next()) {
        ++count;
    }

     if (count == 0) {
        System.out.println("No records found");
    }

    System.out.println("No of rows found from result set in dbExecuteStatement is "+count);

    } catch (SQLException e) {
    e.printStackTrace();
    }

}

     /*
      * This method fetch the result set object from hashMap
      * and iterate it on the basis of fetch size received in req parameter
      */
public void fetchResults(FetchResultsReq fetchResultsReq){

    String uniqueIdForConnectionObject = fetchResultsReq.getDbUniqueConnectionHandlerId();
    Map<Object,Object> dbObject = databaseConnectionDetails.get(uniqueIdForConnectionObject);

    try {
        //Fetch the ResultSet object that was saved by dbExecuteStatement()
        ResultSet rs = (ResultSet) dbObject.get(DatabaseConstants.RESULTSET);
        ResultSetMetaData md = (ResultSetMetaData) dbObject.get(DatabaseConstants.RESULTSETMETADATA);

        System.out.println("ResultSet fethced in fetchResults at server side dao layer======"+rs);
        System.out.println("ResultSet metadata fetched in fetchResults at server side dao layer======"+md);

       int count = 0;
       while (rs.next()) {
           ++count;
        }

        if (count == 0) {
         System.out.println("No records found");
        }
        //Here the row count is not same as row count in dbExecuteStatement()            
        System.out.println("No of rows found from result set in fetchResults is "+count);

    } catch (SQLException e) {
    e.printStackTrace();
    }
    }

}

1 个答案:

答案 0 :(得分:1)

扩展我的评论(和@ Glenn's):

多次使用ResultSet

编写迭代ResultSet的调试代码时,光标移动到结果的末尾。当然,如果你然后调用同一个对象并使用next(),它仍然会在最后,所以你不会再获得任何记录。

如果您确实需要多次从同一ResultSet读取,则需要执行查询以使其返回可滚动的ResultSet。您在创建语句时执行此操作:

Statement stmt = connection.createStatement( 
                              ResultSet.TYPE_SCROLL_INSENSITIVE,
                              ResultSet.CONCUR_READ_ONLY );

connection.createStatement()创建的没有参数的默认语句返回类型为ResultSet.TYPE_FORWARD_ONLY的结果集,而ResultSet对象只能读取一次。

如果结果集类型是滚动不敏感或滚动敏感,则可以使用rs.first()之类的语句重置光标,然后再次获取记录。

保持声明范围

@Glenn的评论非常重要。您的程序现在的工作方式,它可以在整个测试阶段正常工作,然后突然在生产中,您有时在ResultSet中没有记录,并且错误只会偶尔重现 - 调试噩梦

如果生成Statement的{​​{1}}对象已关闭,则ResultSet本身也会关闭。由于您没有自己关闭ResultSet对象,因此将在Statement对象完成后完成此操作。

Statement变量是本地变量,它是我们所知道的stmt唯一的引用。因此,它将由垃圾收集器声明。但是,具有终结器的对象将被降级到终结队列,并且无法知道何时将调用终结器,并且无法控制它。一旦发生,Statement就会被关闭。

因此,请确保在ResultSet旁边保留对语句对象的引用。并确保在完成ResultSet后自己正确关闭它,并且不再使用它。关闭它之后,请记住删除您保留的引用 - 包括语句和结果集 - 以避免内存泄漏。结账很重要,依赖终结者是一个糟糕的策略。如果您不自行关闭它,则可能会在数据库中的某个位置用完游标(取决于DBMS及其配置)。