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

Posted

技术标签:

【中文标题】存储在 hashMap 中的结果集给出零行数【英文标题】:Result set stored in hashMap giving zero row count 【发布时间】:2015-06-21 13:26:25 【问题描述】:

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

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

下面是代码:

  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();
    
    


【问题讨论】:

String uniqueIdForConnectionObject = dbExecuteStatementReq.getDbUniqueConnectionHandlerId(); 是否有可能在两种方法中返回不同的值?您似乎正在使用该唯一 ID 获取 Map,它可能会返回两个不同的地图。 两个问题 - 1. HiveDao1 类是单例吗? 2. 能否附上调用fetchResults方法的代码? 不,我检查了,我使用相同的密钥来检索地图。 @TechnoCrat,不,它不是单例,它实际上是一个 dao 层,当我公开两个服务时,我有一个服务层,一个用于 executeStatement,另一个用于 fetchResults。这些服务实际上是从客户端一步一步调用的。 (a) 请注意,您的调试测试会导致结果集光标移动到末尾,因此任何后续提取都将不起作用。 (b) 如果您一个接一个地立即调用这两个方法,您的问题(假设您删除了调试部分)是否也会发生? 【参考方案1】:

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

多次使用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 中有零记录,并且错误只会偶尔重现 - 一个调试噩梦。

如果产生ResultSetStatement 对象被关闭,ResultSet 本身也被关闭。由于您没有自己关闭您的 Statement 对象,这将在 Statement 对象完成时完成。

stmt 变量是本地变量,它是我们所知道的对 Statement 的唯一引用。因此,它会被垃圾收集器认领。但是,具有终结器的对象被归入终结队列,无法知道何时调用终结器,也无法控制它。一旦发生这种情况,ResultSet 就会关闭,不受您的控制。

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

【讨论】:

以上是关于存储在 hashMap 中的结果集给出零行数的主要内容,如果未能解决你的问题,请参考以下文章

存储过程中的动态 SQL 不返回结果集;在 SSMS 中运行时,我得到了结果

限制结果集行数

可以通过查询结果获取结果集行数吗?

sqlserver 存储过程 返回结果集的 例子

存储过程中的结果集总数

PostgreSQL查询结果集去掉返回行数