Java中JDBC分页通用工具类核心是解耦SQL与分页逻辑,通过拦截SELECT语句、按数据库类型(MySQL/Oracle/PostgreSQL)自动包裹分页语法,并保持原参数顺序,返回新SQL与扩展参数列表,支持安全校验与总记录数查询。

Java 中用 JDBC 实现分页通用工具类,核心在于**解耦 SQL 与分页逻辑**,避免每查一次都手动拼 LIMIT ?, ? 或 ROWNUM,同时适配不同数据库(如 MySQL、Oracle、PostgreSQL)的分页语法差异。
一、设计思路:SQL 拦截 + 参数注入
不修改原始 SQL 字符串,而是提取查询主体(SELECT ... FROM ... WHERE ...),再包裹为带分页的子查询或直接追加 LIMIT/OFFSET。关键点:
- 只处理
SELECT语句,忽略INSERT/UPDATE/DELETE - 保留原有参数占位符(
?)顺序,分页参数(offset、limit)追加在末尾 - 区分数据库类型,由
DatabaseType枚举统一管理方言
二、核心工具类结构(精简版)
以下是一个轻量、可直接复用的 PaginationUtils 类:
立即学习“Java免费学习笔记(深入)”;
public class PaginationUtils {
public enum DatabaseType {
MYSQL, ORACLE, POSTGRESQL
}
<pre class='brush:java;toolbar:false;'>public static class PaginationResult {
public final String sql;
public final List<Object> params;
public PaginationResult(String sql, List<Object> params) {
this.sql = sql;
this.params = params;
}
}
public static PaginationResult buildPagedSql(String originalSql, int offset, int limit, DatabaseType dbType) {
String trimmed = originalSql.trim().toUpperCase();
if (!trimmed.startsWith("SELECT")) {
throw new IllegalArgumentException("Only SELECT statements supported");
}
List<Object> newParams = new ArrayList<>(Arrays.asList(/* 原参数占位符对应值 */));
String pagedSql;
switch (dbType) {
case MYSQL:
pagedSql = originalSql + " LIMIT ?, ?";
newParams.add(offset);
newParams.add(limit);
break;
case POSTGRESQL:
pagedSql = originalSql + " LIMIT ? OFFSET ?";
newParams.add(limit);
newParams.add(offset);
break;
case ORACLE:
// 简化版:使用 ROW_NUMBER() 包裹(支持 Oracle 12c+ 可用 FETCH NEXT)
String wrapped = "SELECT * FROM (SELECT t.*, ROW_NUMBER() OVER (ORDER BY 1) rn FROM ("
+ originalSql + ") t) WHERE rn BETWEEN ? AND ?";
pagedSql = wrapped;
newParams.add(offset + 1);
newParams.add(offset + limit);
break;
default:
throw new UnsupportedOperationException("Unsupported database: " + dbType);
}
return new PaginationResult(pagedSql, newParams);
}}
三、配合 JDBC 使用示例
调用时无需改 DAO 层原有逻辑,只需在执行前包装 SQL 和参数:
立即学习“Java免费学习笔记(深入)”;
String sql = "SELECT id, name FROM user WHERE status = ? AND age > ?";
List<Object> params = Arrays.asList(1, 18);
<p>PaginationUtils.PaginationResult result =
PaginationUtils.buildPagedSql(sql, 20, 10, PaginationUtils.DatabaseType.MYSQL);</p><p>// 执行 JDBC 查询
try (PreparedStatement ps = conn.prepareStatement(result.sql)) {
for (int i = 0; i < result.params.size(); i++) {
ps.setObject(i + 1, result.params.get(i));
}
ResultSet rs = ps.executeQuery();
// 处理结果...
}</p>四、进阶建议
生产环境可进一步增强:
-
自动识别 ORDER BY:Oracle 分页必须有明确排序,若原 SQL 无
ORDER BY,可默认补ORDER BY 1(需谨慎) -
总记录数查询支持:提供
countSqlFor(originalSql)方法,将SELECT xxx替换为SELECT COUNT(*),并剥离LIMIT/OFFSET -
Spring 集成:封装为
@Around切面,通过注解(如@Pageable)自动织入分页逻辑 -
防 SQL 注入提醒:检查原始 SQL 是否含非法字符(如
;、--),日志告警而非抛异常(避免误杀)
不复杂但容易忽略的是:分页参数必须校验非负,且 limit 应设上限(如 ≤ 100),防止恶意拉取全表。


















