Spring Data JPA 的分页魔法:Pageable vs PageRequest,谁才是真正的“分页王”?✨

Spring Data JPA 的分页魔法:Pageable vs PageRequest,谁才是真正的“分页王”?

嘿,各位技术探险家! 今天我们要解锁 Spring Data JPA 的分页秘籍,聊聊 PageablePageRequest 这对“分页双人组”的爱恨情仇! 从它们的关系到使用场景,再到一个让我抓狂的参数陷阱,这篇博客带你从迷雾走向光明,还有流程图助阵,快跟我一起跳进这个技术冒险吧!


第一幕:分页的“魔法钥匙”

分页是啥?

在数据库查询中,分页就像切蛋糕,把一大堆数据分成小块,每次只拿一块。Spring Data JPA 用 PageablePageRequest 来实现这个魔法,但它们到底谁是谁?它们有啥关系?


第二幕:Pageable 和 PageRequest 的“真面目”与“亲密关系”

Pageable:分页界的“规则制定者”

  • 身份:接口(org.springframework.data.domain.Pageable)。
  • 技能
    • getPageNumber():告诉我第几页。
    • getPageSize():每页多大。
    • getOffset():跳过多少条。
    • getSort():怎么排序。
  • 任务:Spring Data JPA 的 Repository 方法用它来识别分页参数。
  • 示例
    Page<InviteCode> findByAdminId(Integer adminId, Pageable pageable);
    

PageRequest:分页界的“执行大师” ️

  • 身份:类(org.springframework.data.domain.PageRequest),实现了 Pageable
  • 技能:通过 PageRequest.of(page, size) 创建分页请求,还能加排序。
  • 任务:在业务代码中构造分页对象,传给需要 Pageable 的方法。
  • 示例
    PageRequest pageRequest = PageRequest.of(0, 10, Sort.by("id").descending());
    Page<InviteCode> page = repository.findByAdminId(7, pageRequest);
    

它们的关系?

  • PageRequestPageable 的实现类

    • Pageable 是一个接口,定义分页的规范,像一份“分页合同”。
    • PageRequest 是具体类,实现了这个接口,是“合同的执行者”。
  • Mermaid 流程图:继承关系

    implements
    extends
    «interface»
    Pageable
    +getPageNumber() : int
    +getPageSize() : int
    +getOffset() : long
    +getSort() : Sort
    «abstract»
    AbstractPageRequest
    PageRequest
    +of(page: int, size: int) : PageRequest
    +of(page: int, size: int, sort: Sort) : PageRequest
    • 解释
      • Pageable 是顶层接口。
      • AbstractPageRequest 是抽象类,提供了部分实现。
      • PageRequest 是最终实现类,可实例化。
  • 实际作用

    • Repository 用 Pageable 接收分页参数。
    • 你用 PageRequest 创建分页对象,传进去,完美配合!

第三幕:一个参数陷阱的“惊魂时刻”

问题来了!

我在写一个分页查询时,定义了这样的 Repository 方法:

Page<InviteCode> findByAdminId(Integer adminId, PageRequest pageRequest);

信心满满地调用:

PageRequest pageRequest = PageRequest.of(0, 10);
Page<InviteCode> page = repository.findByAdminId(7, pageRequest);

结果,服务器甩给我一个 500 错误:

"At least 2 parameter(s) provided but only 1 parameter(s) present in query."

啥?参数不匹配?我懵了。‍♂️

为啥出错?

  • 真相:Spring Data JPA 只认 Pageable 作为分页参数。如果用 PageRequest,它会误以为这是个查询参数!
  • 解析过程
    • 方法名 findByAdminId 生成 SQL:WHERE admin_id = ?1
    • 参数:adminId = ?1pageRequest = ?2
    • 但 SQL 里没用到 ?2,于是报错。
  • 关系的影响:因为 PageRequestPageable 的实现,JPA 期待接口类型来区分分页参数,而不是具体类。
Mermaid 流程图:错误发生过程
调用 findByAdminId(7, pageRequest)
JPA 解析方法签名
识别: adminId=查询参数, pageRequest=查询参数
生成 SQL: WHERE admin_id=?1
错误: 期望2个参数,实际只有1个

第四幕:拨云见日,解决问题!

修复方案 ️

PageRequest 改成 Pageable

Page<InviteCode> findByAdminId(Integer adminId, Pageable pageable);

调用代码不变:

PageRequest pageRequest = PageRequest.of(0, 10);
Page<InviteCode> page = repository.findByAdminId(7, pageRequest);
  • 结果:错误消失,分页完美生效!
  • 原因Pageable 被 JPA 正确识别为分页参数,而 PageRequest 作为它的实现类无缝传入。
Mermaid 流程图:修复后过程
调用 findByAdminId(7, pageRequest)
JPA 解析方法签名
识别: adminId=查询参数, pageable=分页参数
生成 SQL: WHERE admin_id=?1 LIMIT 10 OFFSET 0
成功返回分页数据

第五幕:经验教训与总结

这次我学到了啥?

  1. Pageable 是分页王:Repository 方法里用 Pageable,Spring Data JPA 才会认它是分页参数。
  2. PageRequest 是好帮手:业务代码里用 PageRequest 构造分页,传给 Pageable,它们是接口与实现的黄金搭档!
  3. 别混淆角色:用错了类型,JPA 会把分页参数当查询参数,引发大麻烦。

小建议

  • 日志救命:开启 SQL 日志,看看 JPA 在干啥:
    spring.jpa.show-sql=true
    logging.level.org.hibernate.SQL=DEBUG
    
  • 多练手:试试带排序的分页:
    PageRequest.of(0, 10, Sort.by("id").ascending());
    
  • 理解关系:记住 Pageable 是接口,PageRequest 是实现,Repository 只认老大(Pageable)!

尾声

Pageable 的“规则制定者”到 PageRequest 的“执行大师”,这对分页组合让我又爱又恨。希望这篇博客能帮你在 Spring Data JPA 的分页路上少踩坑!有问题欢迎留言,咱们一起聊技术!✌️

Spring Data JPA 的分页魔法:Pageable vs PageRequest,谁才是真正的“分页王”?✨_第1张图片

你可能感兴趣的:(Spring,Data,JPA,数据库)