Spring Data JPA之分页查询
一、普通:分页+排序
因为PagingAndSortingRepository,我们总是可以传入Sort和Pageable对查询结果进行排序和分页(derived query、example查询和@Query查询都支持)。
// 当查询方法中有多个参数的时候,Pageable/Sort建议做为最后一个参数传入 @Query("select u from User u") Page<User> findALL(Pageable pageable); Page<User> findByNickName(String nickName, Pageable pageable); // 可以返回Page<T>对象,也可以返回List<T>对象
由于JPA(JPQL)不支持Limit,请采用其他方法实现limit需求,https://stackoverflow.com/questions/44565820/what-is-the-limit-clause-alternative-in-jpql
二、单表:分页 + 排序 + 动态查询
- repository继承JpaSpecificationExecutor<T>接口;
- 最终调用Page<T> findAll(@Nullable Specification<T> spec, Pageable pageable)实现“分页+排序”功能
- 构造Specification<T> spec;
- 搜索Specification能得到很多网页结果
interface Specification<T> { Predicate toPredicate(Root<T> root, CriteriaQuery query, CriteriaBuilder cb); }
- 搜索Specification能得到很多网页结果
- 构造Pageable pageable,
- Pageable是可以带Sort的
Pageable sortedByName = PageRequest.of(0, 3, Sort.by("name")); Pageable sortedByPriceDesc = PageRequest.of(0, 3, Sort.by("price").descending()); Pageable sortedByPriceDescNameAsc = PageRequest.of(0, 5, Sort.by("price").descending().and(Sort.by("name")));
- Pageable是可以带Sort的
- 等待补充
三、多表:分页 + 排序 + 动态查询
- 选择主表
- 一般选择带“排序字段”的表作为主表,最终的目的是“分页+排序”只存在于主表
- 主辅表都可以有“动态查询”
- 先操作辅表
- 对辅表进行动态查询等操作,获取逻辑外键的Set集合;
- 把辅表查询得到的逻辑外键的Set集合,返回给主表;
- 再操作主表
- 把辅表返回的逻辑外键的Set集合当做一个查询条件
Predicate predicate = root.get("ip").as(String.class).in(ipCollect);
- 把辅表返回的逻辑外键的Set集合当做一个查询条件
- 完成分页和排序操作
- 还是利用Page<T> findAll(@Nullable Specification<T> spec, Pageable pageable)完成“分页+排序”操作
- 填充辅表字段
- 对分页结果进行Stream操作,补上辅表的字段信息
- 最终的pagesize数量不会很大,补充字段的操作性能消耗不会很大;
- Page<T>的返回结果可以通过在entity中补充@Transient字段,后续进行填充
三、相关问题:
- 最后生成的SQL是什么样子的?
- 是SQL子查询
- 多个表都有排序字段的情况下,怎么确定主表?
- 根据传入的排序字段名,决定哪张为主表,这种情况发生时,大概率是表结构的设计有问题
- 这么做的意义是什么?
- “面向DB编程” VS “面向对象编程”
- 业务逻辑尽可能放在代码里实现,而不是SQL中
- 在互联网开发背景下,更倾向于把DB当中带事务支持的容器,把DB的性能压力解耦到应用层
- 少手写JPQL/SQL,少用JOIN,可以在数据库字段频繁变更,需求频繁变化的情况下,提高开发效率
- 这个方案有什么不好的地方吗?
- JPA在没有物理外键的情况下,无法构建级联关系,这个方法确实可用,但不优雅
- 待补充