如何获取java.sql.ResultSet的大小?

319

这不应该是一个相当简单的操作吗?然而,我发现没有size()length()方法。


12
我很想知道那个省略的原因。 - Slamice
1
我的理解是你想要找到 ResultSet 的大小(以字节为单位),而不是元组的数量... - DejanLekic
在处理数据之前没有正确的维度是非常烦人的,但如果您必须将它们存储在数组中,则可以考虑使用类似List的数据结构,然后使用toArray()方法将其转换为数组。 - AndreaTaroni86
15个回答

302

建议使用 SELECT COUNT(*) FROM ... 查询。

或者

int size =0;
if (rs != null) 
{
  rs.last();    // moves cursor to the last row
  size = rs.getRow(); // get row id 
}

无论哪种情况,您都不需要循环整个数据。


9
ResultSet类中的last()和getRow()方法不是静态方法。 - JeeBee
71
为了简洁起见,在向他人写有关方法的文章时,我总是以这种方式引用它们,不管它们是否为静态的。实际上创建对象实例并调用该方法是暗示的。 - laz
51
为了避免混淆,我使用"SomeClass.staticMethod()"和"SomeClass#instanceMethod()"来表示静态方法和实例方法。 - Jake
9
执行 select count 后如何获取返回的值? - Naftuli Kay
22
ResultSet#last() 方法并不适用于所有类型的 ResultSet 对象,你需要确保使用的是 ResultSet.TYPE_SCROLL_INSENSITIVE 或者 ResultSet.TYPE_SCROLL_SENSITIVE 中的一种。 - Marius Ion
显示剩余11条评论

103
ResultSet rs = ps.executeQuery();
int rowcount = 0;
if (rs.last()) {
  rowcount = rs.getRow();
  rs.beforeFirst(); // not rs.first() because the rs.next() below will move on, missing the first element
}
while (rs.next()) {
  // do your standard per row stuff
}

5
在if(rs.last())代码块内,正确的方法不应该是rs.first(),而应该是rs.beforeFirst()。这样,您就不会在while循环中跳过结果集中的第一条记录进行处理。 - karlgrz
你不要忘记在 if 块之外将光标设置回 beforeFirst 吗? - Gobliins
正如ResultSet文档所述,getRow()适用于TYPE_FORWARD_ONLY结果集,而beforeFirst()对这些结果集会抛出错误。那么这个答案不是有问题吗? - CodePro_NotYet
6
只有在使用滚动不敏感选项创建语句时,此代码才有效: ps=conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); - BullyWiiPlaza

21

如果您有一个类型为ResultSet.TYPE_FORWARD_ONLYResultSet,则希望保持它的状态(而不是切换到ResultSet.TYPE_SCROLL_INSENSITIVEResultSet.TYPE_SCROLL_SENSITIVE以便使用.last())。

我建议使用一种非常好的、高效的技巧,在顶部添加一个第一个虚假/伪行,其中包含行数。

示例

假设您的查询如下:

select MYBOOL,MYINT,MYCHAR,MYSMALLINT,MYVARCHAR
from MYTABLE
where ...blahblah...

你的输出看起来像

true    65537 "Hey" -32768 "The quick brown fox"
false  123456 "Sup"    300 "The lazy dog"
false -123123 "Yo"       0 "Go ahead and jump"
false       3 "EVH"    456 "Might as well jump"
...
[1000 total rows]

只需将您的代码重构为以下内容:

Statement s=myConnection.createStatement(ResultSet.TYPE_FORWARD_ONLY,
                                         ResultSet.CONCUR_READ_ONLY);
String from_where="FROM myTable WHERE ...blahblah... ";
//h4x
ResultSet rs=s.executeQuery("select count(*)as RECORDCOUNT,"
                           +       "cast(null as boolean)as MYBOOL,"
                           +       "cast(null as int)as MYINT,"
                           +       "cast(null as char(1))as MYCHAR,"
                           +       "cast(null as smallint)as MYSMALLINT,"
                           +       "cast(null as varchar(1))as MYVARCHAR "
                           +from_where
                           +"UNION ALL "//the "ALL" part prevents internal re-sorting to prevent duplicates (and we do not want that)
                           +"select cast(null as int)as RECORDCOUNT,"
                           +       "MYBOOL,MYINT,MYCHAR,MYSMALLINT,MYVARCHAR "
                           +from_where);

您的查询输出现在将类似于以下内容:

1000 null     null null    null null
null true    65537 "Hey" -32768 "The quick brown fox"
null false  123456 "Sup"    300 "The lazy dog"
null false -123123 "Yo"       0 "Go ahead and jump"
null false       3 "EVH"    456 "Might as well jump"
...
[1001 total rows]

所以你只需要

if(rs.next())
    System.out.println("Recordcount: "+rs.getInt("RECORDCOUNT"));//hack: first record contains the record count
while(rs.next())
    //do your stuff

有趣,但是如何动态/通用地生成第一个select语句:cast(null as boolean)as MYBOOL等?为此,您需要"select"语句的字段和数据类型的元数据,例如布尔值、字符、整数等...),这可能需要额外的数据库访问,这将抵消所有好处。 - user1697575
当您可以访问所有字段细节并且速度是您的主要关注点(因此需要坚持使用快速的ResultSet.TYPE_FORWARD_ONLY)时,这非常有用。 - Unai Vivi

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

我不明白使用这种方法计算ResultSet大小的缺点是什么。这很棒...没有使用额外的SQL参数。请评论一下这种方法。 - Madeyedexter
6
关键词是性能。想象一下,如果您的结果集有1亿条记录,那么您将会遇到问题。 - Pierre
9
我希望在处理结果之前知道结果集的大小,因为我需要提前制作一个相同大小的数组。正如其他答案中所指出的那样,扫描所有行两次并不总是可行的。 - Ivo
@Ivo,您能否使用List而不是数组,因为会导致明显的性能下降? - jones-chris
1
@jones-chris 谁知道呢,这是3年前的事情,我不知道当时在干什么。虽然我讨厌数组,但我认为使用List可能不可行。无论如何,数组应该比List更高效(除非运行时优化了List方法)。 - Ivo

12

在使用rs.last()时,我遇到了一个异常。

if(rs.last()){
    rowCount = rs.getRow(); 
    rs.beforeFirst();
}
java.sql.SQLException: Invalid operation for forward only resultset

这是因为默认是 ResultSet.TYPE_FORWARD_ONLY,这意味着你只能使用 rs.next()

解决方案是:

stmt=conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
    ResultSet.CONCUR_READ_ONLY); 

14
ResultSet.TYPE_FORWARD_ONLY 切换到 ResultSet.TYPE_SCROLL_INSENSITIVE 通常会导致巨大的性能损失。 - Unai Vivi
3
我在我的表格上进行了测试(10列,187,392行)。我的测试查询并将所有元素加载到字符串中。对于TYPE_FORWARD_ONLY,大约需要1秒钟,对于TYPE_SCROLL_INSENSITIVE,则需要大约7秒钟。当我在SELECT COUNT(*) FROM default_tbl之前使用了SELECT COUNT(*) FROM default_tbl时,总共只需要不到1.5秒钟。我在嵌入式Derby数据库10.11.1.1上进行了测试。 - Vit Bernatik

5

[速度考虑]

这里有很多人建议使用ResultSet.last(),但为此您需要将连接作为ResultSet.TYPE_SCROLL_INSENSITIVE打开,对于Derby嵌入式数据库来说,这比ResultSet.TYPE_FORWARD_ONLY慢高达10倍。

根据我的微型测试结果,在嵌入式Derby和H2数据库中,在SELECT之前调用SELECT COUNT(*)明显更快。

在这里,可以查看我的代码和基准测试结果的详细信息


4
获取ResultSet大小的方法,无需使用ArrayList等,只需要使用以下代码即可:
int size =0;  
if (rs != null)   
{  
rs.beforeFirst();  
 rs.last();  
size = rs.getRow();
}

现在您将获得大小,如果您想要打印ResultSet,在打印之前也请使用以下代码行:

rs.beforeFirst();  

3
这是一种简单的计算行数的方法。
ResultSet rs = job.getSearchedResult(stmt);
int rsCount = 0;

//but notice that you'll only get correct ResultSet size after end of the while loop
while(rs.next())
{
    //do your other per row stuff 
    rsCount = rsCount + 1;
}//end while

5
可以的。但我认为提问者在实际处理行数之前很难确定它们的数量。 我已经遇到了以下两个真实场景:1)记录行的分页 2)在长时间运行的任务中显示已处理的行数以进行进度监控... - ppeterka
预分配数据结构大小是另一个原因。我见过很多库返回包含10个元素的列表,即使只有一个值,因为开发人员在ResultSet中遇到了同样的问题。 - Joseph Lust

2
String sql = "select count(*) from message";
ps =  cn.prepareStatement(sql);

rs = ps.executeQuery();
int rowCount = 0;
while(rs.next()) {
    rowCount = Integer.parseInt(rs.getString("count(*)"));
    System.out.println(Integer.parseInt(rs.getString("count(*)")));
}
System.out.println("Count : " + rowCount);

1
今天,我使用了这个逻辑,但我不知道如何获取RS的计数。
int chkSize = 0;
if (rs.next()) {
    do {  ..... blah blah
        enter code here for each rs.
        chkSize++;
    } while (rs.next());
} else {
    enter code here for rs size = 0 
}
// good luck to u.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接