zoukankan      html  css  js  c++  java
  • 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。

     

     

  • 相关阅读:
    asp.net介绍
    asp.net基本控件
    SQL 查询横表变竖表
    北京北京
    【算法】蓝桥杯dfs深度优先搜索之排列组合总结
    【算法】蓝桥杯dfs深度优先搜索之凑算式总结
    《剑指Offer》面试题3:二维数组中的查找
    《剑指Offer》面试题2:实现Singleton(单例)模式
    《剑指Offer》面试题1:赋值运算符函数
    CentOS6.5x64搭建Hadoop环境
  • 原文地址:https://www.cnblogs.com/funnyboy0128/p/7646430.html
Copyright © 2011-2022 走看看