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

为何Pageable始终返回last为true?实际并非最后一页

Criteria Builder分页查询始终返回"last": true的问题

请求URL:

{{MaterialBaseURI}}/materials/pagination?confType={{confType}}&pageNumber=0&pageSize=5&title=link

我的分页实现代码:

Optional<Pageable> optionalPageable = pageNumber.map(integer -> PageRequest.of(integer, pageSize.get(), Sort.by(Sort.Order.asc(TITLE))));

Page<MaterialMetadata> materialMetadata = materialRepository.findAll((Specification<MaterialMetadata>) (root, criteriaQuery, criteriaBuilder) -> {
            Predicate predicate = criteriaBuilder.conjunction();
            predicate = criteriaBuilder.and(predicate, criteriaBuilder.equal(root.get("conferenceType"), com.logmein.gotomaterialservice.entity.enums.ConferenceType.valueOf(String.valueOf(conferenceType))));

            if (!StringUtils.isEmpty(title)) {
                predicate = criteriaBuilder.and(predicate, criteriaBuilder.like(root.get("title"), "%" + title + "%"));}

            if (startDateTime != null && endDateTime != null && startDateTime != 0 && endDateTime != 0) {
                predicate = criteriaBuilder.and(predicate, criteriaBuilder.between(root.get("createdTime"), startDateTime, endDateTime));}
            else if (startDateTime != null && startDateTime != 0) {
                predicate = criteriaBuilder.and(predicate, criteriaBuilder.greaterThanOrEqualTo(root.get("createdTime"), startDateTime));}
            else if (endDateTime != null && endDateTime != 0) {
                predicate = criteriaBuilder.and(predicate, criteriaBuilder.lessThanOrEqualTo(root.get("createdTime"), endDateTime));
            }
            return predicate;
        }, optionalPageable.get());

接口返回结果:

{
    "content": [
         ...
    ],
    "pageable": {
        "sort": {
            "empty": false,
            "unsorted": false,
            "sorted": true
        },
        "offset": 0,
        "pageNumber": 0,
        "pageSize": 5,
        "paged": true,
        "unpaged": false
    },
    "totalPages": 1,
    "totalElements": 5,
    "last": true,
    "size": 5,
    "number": 0,
    "sort": {
        "empty": false,
        "unsorted": false,
        "sorted": true
    },
    "numberOfElements": 5,
    "first": true,
    "empty": false
}

实际符合条件的记录有15条,pageSize设为5时,last应该为false,但始终返回true,排查不到问题所在。


问题原因

Spring Data JPA的Page对象中last、totalPages、totalElements的值完全依赖于查询时对符合条件的总记录数的统计。出现这个问题的核心是你的查询条件实际匹配的记录数只有5条,而非预期的15条,或者分页查询的统计逻辑出现异常。

排查与修复步骤

  1. 验证like查询的匹配结果
    直接在数据库执行SQL验证匹配总数,替换?为实际的confType值:

    SELECT COUNT(*) FROM material_metadata WHERE conference_type = ? AND title LIKE '%link%';
    

    如果返回结果是5,说明title的匹配逻辑确实只筛选出5条数据,检查数据库中记录的title是否真的包含"link",或参数title是否被意外修改。

  2. 检查conferenceType的转换正确性
    代码中用ConferenceType.valueOf(String.valueOf(conferenceType))转换枚举,添加日志输出转换后的枚举值,确认是否与数据库中conference_type字段的存储值一致。如果枚举转换错误,会过滤掉大量不匹配的数据。

  3. 排查日期过滤条件的影响
    暂时注释掉所有日期相关的过滤代码,重新调用接口查看totalElements是否变为15。如果是,说明startDateTime或endDateTime参数的取值范围过窄,过滤了大部分符合条件的记录。

  4. 手动统计总记录数验证
    在代码中添加手动统计逻辑,确认查询条件的实际匹配数:

    long totalCount = materialRepository.count((Specification<MaterialMetadata>) (root, criteriaQuery, criteriaBuilder) -> {
        Predicate predicate = criteriaBuilder.conjunction();
        predicate = criteriaBuilder.and(predicate, criteriaBuilder.equal(root.get("conferenceType"), com.logmein.gotomaterialservice.entity.enums.ConferenceType.valueOf(String.valueOf(conferenceType))));
        if (!StringUtils.isEmpty(title)) {
            predicate = criteriaBuilder.and(predicate, criteriaBuilder.like(root.get("title"), "%" + title + "%"));
        }
        if (startDateTime != null && endDateTime != null && startDateTime != 0 && endDateTime != 0) {
            predicate = criteriaBuilder.and(predicate, criteriaBuilder.between(root.get("createdTime"), startDateTime, endDateTime));
        } else if (startDateTime != null && startDateTime != 0) {
            predicate = criteriaBuilder.and(predicate, criteriaBuilder.greaterThanOrEqualTo(root.get("createdTime"), startDateTime));
        } else if (endDateTime != null && endDateTime != 0) {
            predicate = criteriaBuilder.and(predicate, criteriaBuilder.lessThanOrEqualTo(root.get("createdTime"), endDateTime));
        }
        return predicate;
    });
    System.out.println("Total matching records: " + totalCount);
    

    如果输出的totalCount是5,说明查询条件确实只匹配5条数据;如果是15,说明Spring Data JPA分页的统计逻辑存在异常,需检查依赖版本或配置是否有问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 23:30:43