JPA實現復雜條件分頁查詢


  相信熟悉Hibernate的人對於ORM給編程帶來的便利於快捷一定不陌生,相對於MyBatis等需要編寫復雜的SQL語句,ORM映射為我們帶來的便利顯而易見。但是,在獲得便利的同時,失去的便是靈活性,這里不是說Hibernate不靈活,只是針對初學者來說,要掌握靈活的技巧,需要的成本相對較高。過去的半年里,在項目中通過Spring Cloud實現了一套關於為服務的基礎架構,其中在數據持久層采用的是Spring Data JPA,對於曾經用過Hibernate的人來說,選擇JPA會十分容易上手,因為語法一切都是那么熟悉。但是,在涉及到復雜的查詢的時候,尤其是多條件查詢的時候,如果通過命名方式實現,長長的方法名將是代碼顯得十分的不優雅。這個時候,大多數人會選擇使用NativeQuery,通過編寫SQL語句來實現,這種方式導致的結果就是項目代碼中遍地是SQL,隨着時間的推移,項目已經失去了使用JPA的初衷。能否有一種方式,在保障JPQL的風格里完成這種復雜的查詢呢?這里介紹一種簡單的方式:JpaSpecificationExecutor

  JpaSpecificationExecutor不屬於JpaRepository體系,它允許自定義查詢條件實現查詢。通過源碼可以發現,JpaSpecificationExecutor提供了如下幾個方法:

  public interface JpaSpecificationExecutor<T> {

  T findOne(Specification<T> spec);

  List<T> findAll(Specification<T> spec);

  Page<T> findAll(Specification<T> spec, Pageable pageable);

  List<T> findAll(Specification<T> spec, Sort sort);

  long count(Specification<T> spec);

  }

  其中,Page<T> findAll(Specification<T> spec, Pageable pageable)是不是看起來很熟悉,因為在JpaRepository我們用的十分常見,只不過這里的入參不同,Pageable提供了排序分頁的功能,Specification允許我們自定義查詢條件,繼續進入源碼:

public interface Specification<T> {

  Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb);

}

沒錯,這個接口提供了唯一方法toPredicate,通過該方法構造出一個復雜查詢條件。Root代表的是實體,CriteriaBuilder是條件構造器,通過該方法,我們構造出復雜的查詢條件並返回,JPA便會自動的處理轉換查詢。下面以一個小demo描述使用JpaSpecificationExecutor實現復雜查詢的步驟:

1、DAO層繼承JpaSpecificationExecutor接口(當然,如果需要JpaRepository相關方法,同時繼承即可)

@Component
public interface SpeciRepository extends JpaSpecificationExecutor<TestVO>,JpaRepository<TestVO, Long>{
}

2、Service構造查詢條件,並調用DAO層

@Service

@Transactional

public class MySpeciServiceImpl implements MySpeciService {

     @Autowired  private SpeciRepository speciRepository;    

  @Override  public Page<TestVO> findByPageAndParams(final TestVO param, int pageNumber,int pageSize) {   

    Pageable pageable=new PageRequest(pageNumber, pageSize);  //分頁信息   

    Specification<TestVO> spec = new Specification<TestVO>() {        //查詢條件構造       

       @Override    public Predicate toPredicate(Root<TestVO> root, CriteriaQuery<?> query,CriteriaBuilder cb) {    

        Path<String> name = root.get("name");      

        Path<Integer> age = root.get("age");          

        Predicate p1 = cb.like(name, "%"+param.getName()+"%");     

        Predicate p2 = cb.lt(age, param.getAge());     

           Predicate p = cb.and(p1, p2);         

         return p;   

       }  

     };   

    return speciRepository.findAll(spec, pageable);

   }

}

通過以上兩個步驟,就能實現一個基本的復雜分頁查詢,其實很簡單。其中的關鍵點就是查詢條件的構造,可以通過CriteriaBuilder提供的相關謂詞進行組裝。詳細用法這里不累述,有興趣或有需要可自行baidu。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM