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

Spring Boot中JPA Projection原生查询分页异常问题求助

Spring Boot原生查询分页+JPA Projection异常排查:size>1返回空content

问题现象

  • 采用Spring Boot原生SQL做分页查询,因查询语句包含字段别名,使用JPA Projection接口映射DTO字段
  • Postman调用接口时,size=1能正常返回1条记录;但size>1时,返回结果的content数组为空
  • 直接在MySQL客户端执行相同SQL语句,可正常返回所有预期数据

相关代码片段

实体类示例

@Entity
@Table(name = "target_table")
public class TargetEntity {
    @Id
    private Long id;
    private String originalField1;
    private Integer originalField2;
    // 其他字段及getter/setter
}

JPA Projection接口

public interface TargetProjection {
    String getAliasField1();
    Integer getAliasField2();
    // 与SQL查询别名对应的getter方法
}

Repository层代码

@Repository
public interface TargetRepository extends JpaRepository<TargetEntity, Long> {
    @Query(value = "SELECT t.original_field1 AS aliasField1, t.original_field2 AS aliasField2 " +
                   "FROM target_table t WHERE t.status = 1",
           countQuery = "SELECT COUNT(*) FROM target_table t WHERE t.status = 1",
           nativeQuery = true)
    Page<TargetProjection> queryPagedData(Pageable pageable);
}

Service层代码

@Service
public class TargetService {
    @Autowired
    private TargetRepository targetRepository;

    public Page<TargetProjection> getPagedData(int page, int size) {
        Pageable pageable = PageRequest.of(page, size);
        return targetRepository.queryPagedData(pageable);
    }
}

Controller层代码

@RestController
@RequestMapping("/api/data")
public class TargetController {
    @Autowired
    private TargetService targetService;

    @GetMapping
    public ResponseEntity<Page<TargetProjection>> getPagedData(
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "10") int size) {
        Page<TargetProjection> result = targetService.getPagedData(page, size);
        return ResponseEntity.ok(result);
    }
}

Postman响应示例

size=1时的正常响应

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

size>1时的异常响应

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

排查方向与解决方案

  1. 校验Projection方法与别名的映射规则
    确保Projection接口的getter方法名与SQL别名严格匹配驼峰转换规则:比如SQL别名是alias_field1,对应getAliasField1();如果SQL直接用驼峰别名aliasField1,则直接对应getAliasField1(),大小写和前缀不能出错。

  2. 查看最终执行的SQL语句
    在application.yml中开启SQL日志:

    logging:
      level:
        org.hibernate.SQL: debug
        org.hibernate.type.descriptor.sql.BasicBinder: trace
    

    对比日志中Spring Data JPA自动拼接LIMIT/OFFSET后的SQL,与手动执行的SQL是否完全一致,排查分页参数是否正确传递。

  3. 检查实体主键映射
    JPA处理分页时可能依赖实体主键进行结果集处理,确认实体类的@Id字段与数据库表主键完全对应,避免因主键映射错误导致分页逻辑异常。

  4. 改用类类型Projection尝试
    若接口类型Projection存在兼容性问题,可定义DTO类(带全参构造函数),将Repository方法返回类型改为Page<TargetDto>,SQL别名与DTO字段名对应,测试是否能正常返回分页数据。

  5. 升级数据库驱动版本
    部分旧版本MySQL驱动在处理原生分页+Projection组合场景时存在bug,尝试升级mysql-connector-java或mysql-connector-j到最新稳定版。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 01:10:15