一、普通:分頁+排序
因為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在沒有物理外鍵的情況下,無法構建級聯關系,這個方法確實可用,但不優雅
- 待補充