You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jooq是否具备QueryDSL式自动计数分页的便捷查询方法?

在jOOQ中实现自动分页+计数查询

jOOQ提供了简洁的方式实现类似QueryDSL的自动分页查询,无需手动拆分计数查询和数据查询,下面是具体实现方案:

方案1:使用fetchPage()方法(推荐)

jOOQ 3.12及以上版本提供了Page类型和ResultQuery.fetchPage()方法,能自动完成计数查询和数据查询,返回包含总条数和分页数据的Page对象。

优化后的示例代码:

var post = Tables.POST;
var postChannel = Tables.POST_CHANNEL;
var postTag = Tables.POST_TAG;

// 构建完整的查询条件
Condition condition = noCondition();
if (StringUtils.hasText(title)) {
    condition = condition.and(post.TITLE.like("%" + title + "%"));
}
if (StringUtils.hasText(reference)) {
    condition = condition.and(post.REFERENCE.like("%" + reference + "%"));
}
if (enabled != null) {
    condition = condition.and(post.ENABLED.eq(enabled));
}
if (publicly != null) {
    condition = condition.and(post.PUBLICLY.eq(publicly));
}
if (createAtStart != null || createAtEnd != null) {
    condition = condition.and(post.CREATE_AT.between(
        createAtStart == null ? null : createAtStart.atStartOfDay(), 
        createAtEnd == null ? null : createAtEnd.atTime(LocalTime.MAX)
    ));
}
if (channelId != null) {
    condition = condition.and(exists(
        selectOne().from(postChannel)
            .where(postChannel.POST_ID.eq(post.ID).and(postChannel.CHANNEL_ID.eq(channelId)))
    ));
}
if (tagId != null) {
    condition = condition.and(exists(
        selectOne().from(postTag)
            .where(postTag.POST_ID.eq(post.ID).and(postTag.TAG_ID.eq(tagId)))
    ));
}

// 构建分页查询
ResultQuery<Record> query = ctx.select(post.ID, post.VERSION, post.PREVIEW, post.REFERENCE, post.PATH, 
        post.KEYWORDS, post.TITLE, post.CREATE_AT, post.ENABLED, post.PUBLICLY, post.TOC, post.POSTER)
    .from(post)
    .where(condition)
    .orderBy(post.CREATE_AT.desc());

// 自动执行计数查询+分页数据查询
Page<Record> pageResult = query.fetchPage(page.offset() / page.limit(), page.limit());

// 转换为自定义Paged对象
if (pageResult.total() == 0) {
    return Paged.empty();
}
List<PostDTO> ret = pageResult.map(r -> r.into(PostDTO.class));
return Paged.of(pageResult.total().intValue(), ret);

方案2:手动复用查询对象获取计数

如果你需要更灵活的控制,也可以复用已构建的查询对象,通过fetchCount()获取总条数,再执行分页查询:

// 构建查询(同方案1)
ResultQuery<Record> query = ctx.select(...)
    .from(post)
    .where(condition)
    .orderBy(post.CREATE_AT.desc())
    .offset(page.offset())
    .limit(page.limit());

// 获取总条数(自动忽略offset/limit/orderBy)
long total = query.fetchCount();
if (total == 0) {
    return Paged.empty();
}

// 获取分页数据
List<PostDTO> ret = query.fetch(r -> r.into(PostDTO.class));
return Paged.of((int) total, ret);

关键说明

  • fetchPage()方法会自动优化计数查询:它会移除原查询中的SELECT列、ORDER BY、OFFSET、LIMIT,只保留FROM和WHERE条件来执行计数,和QueryDSL的fetchResults()逻辑一致。
  • 修正了原代码中的两处变量错误:reference条件误用title变量、publicly条件误用enabled变量。

内容的提问来源于stack exchange,提问作者KevinBlandy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 17:27:46