相信熟悉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。

最新文章

  1. 我的git学习
  2. KMP快速字符串匹配
  3. Device disconnected
  4. 【Android】Fragment如何获取子Fragment
  5. svg图片转换为WEB字体图标
  6. Selenium Web 自动化 - 项目持续集成(进阶)
  7. JVM的运行原理以及JDK 7增加的新特性(一)
  8. 【已解决】报异常:java.lang.ArithmeticException: / by zero
  9. python 解方程
  10. 【Python3练习题 020】 求1+2!+3!+...+20!的和
  11. osx升级到10.10后,使用pod install报错解决的方法
  12. Java和C#差异点
  13. iOS边练边学--transform的简单介绍并且用transform实现键盘处理
  14. linux c++ 多线程心得
  15. android中Zing二维码扫描,二维码生成
  16. MySql笔记之数据表
  17. ACboy needs your help-分组背包模板题
  18. 记一次肉机事件--yam
  19. Linux模块机制浅析_转
  20. rtsp 播放器

热门文章

  1. ASP.NET/MVC/Core的HTTP请求流程
  2. SQL Server内幕之数据页
  3. 同事搭一个测试RAC说节点2发现idle了,报ORA-00304
  4. 【Teradata TTU】Windows TTU安装工具列表
  5. sql的基本语法
  6. HNOI2019 苟命记
  7. PLC
  8. mysql优化一之查询优化
  9. 如何面对被抛弃的System.Data.OracleClient
  10. 【Android Studio安装部署系列】二十一、Android studio将项目上传到github中