在不支持 LIMIT/OFFSET 的數據庫(如早期 Oracle、SQL Server)中,可利用 JDBC ResultSet.TYPE_SCROLL_INSENSITIVE 游標實現分頁。
public void getData(String sql, int startNo, int maxCount) {
try (Connection conn = ConnectionUtil.getConnection();
PreparedStatement ps = conn.prepareStatement(sql,
ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY)) {
ps.setMaxRows(startNo + maxCount - 1); // 只讀取到目標頁末尾
ResultSet rs = ps.executeQuery();
rs.first(); // 移至第一行
rs.relative(startNo - 2); // 移至目標頁第一行(相對移動)
while (rs.next()) {
System.out.println(rs.getInt(1));
}
} catch (SQLException e) { e.printStackTrace(); }
}
原理:setMaxRows 限制數據庫返回行數,游標再定位到起始行。
public void getDataFromAll(String sql, int startNo, int maxCount) {
try (Connection conn = ConnectionUtil.getConnection();
PreparedStatement ps = conn.prepareStatement(sql,
ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY)) {
ResultSet rs = ps.executeQuery();
rs.first();
rs.relative(startNo - 1); // 移至起始行
int i = startNo - 1;
while (i < startNo + maxCount - 1 && !rs.isAfterLast()) {
System.out.println(rs.getInt(1));
i++;
rs.next();
}
} catch (SQLException e) { e.printStackTrace(); }
}
原理:一次性查所有數據,在客戶端游標中跳過前面行。
| 維度 | 方案一 | 方案二 |
|---|---|---|
| 網絡傳輸量 | 少(受 maxRows 限制) | 大(全量傳輸) |
| 數據庫負載 | 低 | 高 |
| 適用數據量 | 大表 | 小表 |
| 游標類型要求 | TYPE_SCROLL_INSENSITIVE | TYPE_SCROLL_INSENSITIVE |
LIMIT offset, size,性能更優。INSENSITIVE 類型,不感知他人提交的修改,適合只讀分頁。ResultSet、Statement、Connection(建議用 try-with-resources)。可滾動游標是早期分頁常用技巧,理解其原理有助於維護舊系統;新項目請優先使用數據庫原生分頁語法。