【问题标题】:JDBC ResultSet total rowsJDBC ResultSet 总行数
【发布时间】:2010-06-14 19:06:37
【问题描述】:

我正在我的应用程序中实现分页。为此,我运行一个查询并获得一个 ResultSet。
现在我想获取此 ResultSet 中的记录总数以进行分页计算。
我怎样才能得到这个?我不想执行额外的 SQL,这会给我总行数。

【问题讨论】:

  • 只是好奇这是一个网络应用程序吗?如果我们不是在谈论来自查询的 1000 多条记录,您可以非常轻松地实现一个 java 脚本分页,并且不必为每个页面打后端。

标签: java jdbc pagination resultset rowcount


【解决方案1】:

另一种选择是将计数聚合添加为查询中的子查询列。如果您的数据库有点智能,它只会执行一次。您应该能够使用您喜欢的数据库中的查询分析器轻松检查这一点。

SELECT id,username,(SELECT COUNT(id) FROM users) FROM users;

【讨论】:

  • 我推荐使用 java 解决方案,因为如果我们有一个复杂的查询,这将有性能成本
  • 除非您使用的数据库具有非常原始的查询优化器,否则计算结果集中的行数不会比稍后在 Java 端进行计算成本更高。
【解决方案2】:

常规做法是将ResultSet 映射到List<Entity>,其中Entity 是一个代表实际数据的javabean,例如UserProductOrder

然后,您可以使用ListList#size() 方法来获取行数。

List<Entity> entities = entityDAO.list();
int rows = entities.size();

if (entities.isEmpty()) {
    // It is empty!
} else if (entities.size() == 1) {
    // It has only one row!
} else {
    // It has more than one row!
}

【讨论】:

  • 感谢您的回复,实际上我不想获取集合中的所有行,因为我只想在页面上显示 10 行,因此我的分页计算帮助我从结果集中仅获取 10 行。为此,我需要结果集中的总行数。
  • 然后触发两个查询:一个获取COUNT(*)(或者更好,COUNT(pk)),另一个获取感兴趣的行。虽然可能不完全适合您的要求(JSF Web 应用程序),但您可能会从 this article 中获得一些有用的见解。
【解决方案3】:
int totalRows = 0;
    try    {
        resultSet.last();
        totalRows = resultSet.getRow();
        resultSet.beforeFirst();
    } catch(Exception ex)  {
               return 0;
          }
    return totalRows ;

【讨论】:

  • 调用resultSet.getRow() 直接给我返回0。现在我看到它的意思是resultSet的当前位置到开始的行数。我在想为什么它是这样设计的。
【解决方案4】:

如果我没记错的话,ResultSet 的默认行为不是一次获取所有行,因此无法从对象本身知道在没有第一次迭代的情况下会从查询返回多少行(并因此检索)所有这些。对于特定数据库的特定 JDBC 驱动程序,您可能会得到不同的行为。

请问为什么先运行 COUNT() 查询成本太高?与检索实际值的成本相比,它应该不会太贵。

【讨论】:

  • 这是最佳实践,运行查询以获取计数?有什么办法吗?
  • 我不知道这是否是最佳实践,但如果您先运行计数查询(例如,SELECT COUNT(*) as NumExpectedRows FROM table WHERE whatever;),您可以预测您可以从结果集中获得的行,而无需构建整个集合。数据库应该对此进行优化(检查您的特定供应商文档)。需要注意的是,在您执行“真实”查询之前,行数不应改变。
  • 是的,两个查询之间的计数可能会发生变化,因此可能不准确。但是在这个应用程序中,计数也可能在用户请求页面 1 和页面 2 的时间之间发生变化,因此我们无论如何都不能保证完全准确。
【解决方案5】:

来自BalusC's的评论回复:

[...] 实际上我不想获取集合中的所有行,因为我只想在页面上显示 10 行,因此我的分页计算帮助我从结果集中仅获取 10 行。为此,我需要结果集中的总行数

您只需要向数据库询问大约 10 行表的大小。因此,您实际上对数据存储有两 (2) 个问题,这等于两 (2) 个选择查询。按照Uri 的建议去做,不要关心“最佳实践”。如果有一天有人提出了一种更好的做法,您仍然可以决定是否调整您的代码。

【讨论】:

    【解决方案6】:

    计算列表大小来获取记录数是没有意义的,因为我们正在实现分页并且不应该一次加载整个结果集。

    我在数据库级别使用 ROW_NUM 来实现分页逻辑。我们需要获取尽可能多的记录以在屏幕上显示。

    示例:select * from Emp where rownum>=:beginRecord and rownum

    ***** 逻辑相同,但语法可能会根据数据库的类型而改变。如果我们需要对任何列进行排序,则需要使用嵌套查询。*

    我相信,count(*) 是昂贵的操作,而我更喜欢分区。

    Select Eno, Ename , (select count() from emp) as record_count from Emp -- 昂贵 选择 Eno, Ename , count() over (partition by eno) as record_count from Emp -- Preferred one。

    ***** 语法分区可能会根据数据库的类型而有所不同。*

    我考虑过Oracle数据库。

    【讨论】:

      【解决方案7】:

      除了 Fathah 解决方案,您还可以使用此代码,还请注意,由于它是内存指针,因此此解决方案没有性能问题:

      int totalRows = 0;
      if(rowSet.last()) {
         totalRows = rowSet.getRow();
      }
      rowSet.beforeFirst();
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-06-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-07-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多