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> {ide

  T findOne(Specification<T> spec);ui

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

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

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

  long count(Specification<T> spec);接口

  }ci

  其中,Page<T> findAll(Specification<T> spec, Pageable pageable)是否是看起來很熟悉,由於在JpaRepository咱們用的十分常見,只不過這裏的入參不一樣,Pageable提供了排序分頁的功能,Specification容許咱們自定義查詢條件,繼續進入源碼:get

public interface Specification<T> {

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

}

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

一、DAO層繼承JpaSpecificationExecutor接口(固然,若是須要JpaRepository相關方法,同時繼承便可)

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

二、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。

相關文章
相關標籤/搜索