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

12 浏览
0 Comments

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

这不是一个相当直接的操作吗?然而,我发现既没有size()方法,也没有length()方法。

0
0 Comments

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

问题出现的原因是:如果你有一个类型为ResultSet.TYPE_FORWARD_ONLY的ResultSet,你希望保持这种状态(而不是切换到ResultSet.TYPE_SCROLL_INSENSITIVE或ResultSet.TYPE_SCROLL_INSENSITIVE以便能够使用.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 "
                           + "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"));
while(rs.next())
    //do your stuff

这种方法非常有趣,但是如何动态/通用地生成第一个select语句:cast(null as boolean) as MYBOOL,等等?为此,你需要"select"语句字段和数据类型的元数据,如boolean、char、int等...),这可能需要额外的数据库访问,这样会抵消所有的好处。

当你可以访问所有字段细节并且速度是你的主要关注点时(因此需要使用快速的ResultSet.TYPE_FORWARD_ONLY),这种方法非常有用。

0
0 Comments

问题的出现原因是在处理ResultSet时可能会出现漏掉第一条记录的情况。解决方法是在判断ResultSet是否有数据后,使用rs.beforeFirst()将游标移动到第一条记录之前,以确保第一条记录不被漏掉。

以下是整理后的

在Java中,我们经常需要处理数据库查询结果集ResultSet的大小。然而,获取ResultSet的大小并不是一件简单的事情。下面是一个解决该问题的示例代码:

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
}

在上述代码中,我们首先执行查询操作并获取ResultSet对象rs。然后,我们定义一个变量rowcount来保存ResultSet的大小。在if(rs.last())代码块中,我们使用rs.last()方法将游标移动到结果集的最后一行,并使用rs.getRow()方法获取当前行的索引,即ResultSet的大小。接着,我们使用rs.beforeFirst()方法将游标移动到第一条记录之前,以确保第一条记录不被漏掉。最后,我们使用while(rs.next())循环来遍历ResultSet中的每一条记录进行处理。

然而,有一些读者指出了上述代码中的一些问题。他们认为在if(rs.last())代码块中,应该使用rs.beforeFirst()方法而不是rs.first()方法,以免漏掉第一条记录。此外,还有读者指出在if代码块之外也要将游标移动到第一条记录之前。

然而,根据ResultSet的官方文档,getRow()方法只适用于TYPE_FORWARD_ONLY类型的ResultSet,而beforeFirst()方法对此类型的ResultSet会抛出错误。因此,上述解决方法并不适用于所有情况。

实际上,只有在创建Statement对象时使用了scroll insensitive选项时,上述解决方法才有效。具体代码如下:

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

通过使用scroll insensitive选项创建Statement对象,我们就可以正确地使用rs.last()和rs.beforeFirst()方法来获取ResultSet的大小,并且不会出现漏掉第一条记录的问题。

总结起来,要想获取Java中ResultSet的大小,我们可以使用上述代码片段,但需要确保在创建Statement对象时使用了scroll insensitive选项。这样,我们就可以避免漏掉第一条记录,并正确地获取ResultSet的大小。

0
0 Comments

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

要获取java.sql.ResultSet的大小,有两种常见的方法:

1. 执行SELECT COUNT(*) FROM ...查询语句。

2. 使用ResultSet.last()ResultSet.getRow()方法。

以上两种方法都不需要遍历整个数据集。

第一种方法中,SELECT COUNT(*)查询语句会返回结果集的大小。

第二种方法中,我们首先将游标移动到最后一行,然后使用getRow()方法获取行号。

然而,需要注意的是,ResultSet#last()方法并不适用于所有类型的ResultSet对象,你需要确保使用的是ResultSet.TYPE_SCROLL_INSENSITIVEResultSet.TYPE_SCROLL_SENSITIVE类型的结果集。

如果结果集是从存储过程调用返回的,你可以在存储过程内部执行SELECT COUNT(*)语句,或者存储过程返回一个临时视图,然后调用者可以对该视图执行SELECT COUNT(*)

如果你不能更改存储过程,因为它来自其他地方,那么可能无法高效地计算结果集的大小。但是,如果必须手动计算行数,建议在服务器端执行计数操作(比如使用临时存储过程)。

关于为什么获取结果集的大小这么困难,为什么API中没有提供ResultSet#size()方法,某些情况下了以下原因:

获取结果集的大小需要在整个结果集实例化之后才能得知,这样做效率低下,因为实例化所有行需要消耗内存、I/O和处理时间。当读取前向只读结果集(有时也包括可滚动结果集)时,数据库只在需要时读取行(可能会预读一些)。因此,客户端可能在处理某些行时,数据库正在读取更多行,这样可以提高效率并减少内存使用。

另外,有人问道select count(*) from table是一个O(n)操作吗?使用ResultSet::last()方法是否也是一个O(n)操作?答案是,对于某些数据库,比如MS SQL Server,默认情况下使用前向只读游标的ResultSet::last()方法是O(n)的。如果要实现O(1)的last()操作,则需要使用可滚动和静态游标。但是这些游标类型要求服务器将整个键集存储在内存中。服务器不能事先知道你将抛弃结果只使用行数,因此必须建立查询计划,假设你将使用所有数据。

因此,如果你在之后还需要使用数据,间接地建议使用ResultSet.last()方法是最佳解决方案。实际上,我对内嵌的Derby和H2数据库进行的速度测试显示,即使在之后还要使用数据,只需在数据库中先执行SELECT COUNT(*),然后以ResultSet.TYPE_FORWARD_ONLY的模式获取结果也更快。

0