我的类中有两个方法,首先我调用方法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();
}
}
}
答案 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及其配置)。