Jaybird (Firebird JDBC) ResultSet FetchSize -- 分页持久查询

Jaybird (Firebird JDBC) ResultSet FetchSize -- Pagination long lasting queries

我正在尝试寻找一种方法来强制 jaybird 在 ResultSet 中执行 "pagination"。假设我们有一些持久的 sql 查询(它 returns 例如 15 秒内 5000 行)。但是,获取前 50(随机)行只需要几分之一秒。只要我们不在查询中添加 order by 子句,服务器就会快速 returns 第一行,这些行可以立即显示在客户端应用程序中。这是 flamerobin 客户端的默认行为。

我尝试通过设置如下代码中的语句参数来模拟此行为,但没有成功。有没有办法强制 jaybird 不将所有行加载到 ResultSet?我想 stmt.setFetchSize(50) 方法有这个目的,但它可能是错误的。使用的 Jaybird 版本是 2.2.7,使用的 Firebird 版本是 2.5.4。谢谢你的建议。

String user = "user";
String pass = "pass";
Connection conn = DriverManager.getConnection(s, user, pass);
conn.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
conn.setAutoCommit(false);
Statement stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
stmt.setFetchSize(50);
stmt.setFetchDirection(ResultSet.FETCH_FORWARD);
ResultSet rs = null;
String sql = "select * from TABLE"; //long lasting select 
boolean ok = stmt.execute(sql);
if (ok) {
    rs = stmt.getResultSet();
    while (rs.next()) {
         //do something
    }
}
if (rs != null) {
    rs.close();
}

if (stmt != null) {
    stmt.close();
}

我尝试实现与 flamerobin 客户端相同的想法——将数据动态加载到 table(仅当我们需要它们时——在 table 中向下滚动)。我们开发的应用程序是两层 ERP 系统的客户端(DB 服务器 firebird,netbeans 平台上的客户端)。我们编写了一些数据库组件,按照 "interbase Delphi components" 过去所做的相同原则用数据填充 JXTable。上面的代码是简化的,在组件代码中我们将前 100 行加载到 JTable table 模型,当用户向下滚动时我们加载另外 100 行等。但是我注意到前 100 行的加载时间是就像我们将所有行加载到数据集一样。那就是代码

boolean ok = stmt.execute(sql);
if (ok) {
    rs = stmt.getResultSet();
    int rows = 0;
    while (rs.next() rows < 100) {
         //do something
         rows++;
    }
}

几乎与第一块源代码花费了相同的时间。似乎 stmt.execute(sql) 命令一直等到所有 select 行都从服务器返回。但是我设置我想要获取 50 行块,所以我认为 while 循环将在从数据库服务器获取前 50 行后立即开始。所以我想在获取前 50 行后开始 while 循环(就像我设置 stmt.setMaxRows(50) 一样),但我希望有机会打开结果集并按需获取其他行。

使用 setFetchSize 通常完全符合您的预期:它将以指定大小的批次获取行(当 Firebird 3 认为批次太大时,它可以决定减少 return)。

但是,由于您在连接字符串中指定了 defaultHoldable,因此结果集是 HOLD_CURSORS_OVER_COMMIT,并且可保存的结果集在被 returned 之前完全缓存在客户端。

您需要将此特定语句的可保持性设置为 CLOSE_CURSORS_AT_COMMIT,或者 - 如果您对所有语句都这样做 - 只需从连接字符串中删除 defaultHoldable