Spring Data JPA带条件分页查询实现原理

所属分类: 软件编程 / java 阅读数: 47
收藏 0 赞 0 分享

最新Spring Data JPA官方参考手册 Version 2.0.0.RC2,2017-07-25

https://docs.spring.io/spring-data/jpa/docs/2.0.0.RC2/reference/html/

JPA参考手册 (找了半天, 在线版的只找到这个)

https://www.objectdb.com/java/jpa

Spring Data JPA的Specification类, 是按照Eric Evans的《领域驱动设计》书中Specification的概念和语义来定义查询条件的API。
使用Spring Data JPA, 我们一般将自己的dao接口继承CrudRepository接口和JpaSpecificationExecutor接口, 由框架生成代理类来完成具体的调用, 而不用自己写daoImpl实现类, 因为这两个接口自带了很多方法, 如果我们写实现类会发现一上来就需要实现十来个方法, 比较麻烦。

其中CrudRepository接口主要负责增/删/改的操作, JpaSpecificationExecutor接口主要负责查询的操作, 另外, 框架还支持在dao接口的方法名上定义一些简单的语义来进行增删改查, 底层会对应地做具体实现。

那如何封装具体的查询条件呢?

在service层调用dao接口从JpaSpecificationExecutor继承的抽象查询方法, 它就会自动让你准备相关实参, 其中Specification对象就是经常用在条件查询的方法的一个形参, 也就是说, 封装查询条件的过程转移到service层了。

我们一般以匿名内部类的方式new一个Specification对象, 实现其中的toPredicate方法, 举个例子,

Specification<Person> specification = new Specification<Person>() {
      @Override
      public Predicate toPredicate(Root<Person> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
      ...
};

其中, Predicate, Root, CriteriaQuery, CriteriaBuilder都是javax.persistence包中的接口, 方法的这3个实参由框架交给我们。

Predicate意思是"描述语", 就是我们封装完查询条件后要交给Specification一个清楚的描述, 要怎么组合sql语句去查询。

Root表示为泛型里的Person对象描述一个根位置, 可以从这个根位置去取该对象的属性, 以及属性的属性, 类似对象导航的意思, 比如要取Person地址属性的城市, 就可以root.get("address").get("city").as(String.class), 其返回值是一个Expression对象;

CriteriaQuery代表条件查询,主要提供where、group by、having、order by等。

CriteriaBuilder用于构造筛选条件,主要提供equal、and、or、lt、gt、between、like等, 以及获得CriteriaQuery、CriteriaUpdate、CriteriaDelete对象。构造每个筛选条件一般需要Expression类型作为实参, 可以通过Root对象调用get()方法得到。如果有多个筛选条件, 调用criteriaBuilder的and、or等方法连接起来, 一般是链式调用的形式。

举个简单的实际例子:

//带条件的分页查询, 根据person的first_name和last_name进行模糊查询
//为了直观, 假设两个字段都存在且不为空串, 省掉非空判断和对应的处理
public Page<Person> findSearch(Person person, int page, int size) {
  Specification<Person> specification = new Specification<Person>() {
   @Override
   public Predicate toPredicate(Root<Person> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
      Predicate predicate1 = criteriaBuilder.like(root.get("first_name").as(String.class), "%"+person.getFirstName()+"%");
      Predicate predicate2 = criteriaBuilder.like(root.get("last_name").as(String.class), "%"+person.getLastName()+"%");
        Predicate finalPredicate = criteriaBuilder.and(predicate1, predicate2);
       return finalPredicate;
   }
  };
  PageRequest pageRequest = PageRequest.of(page-1, size);
  return personDao.findAll(specification, pageRequest);
}

当然这都是JPQL的语法了, 很多开发者也经常在dao接口中直接写SQL语句来让框架查询, 使用起来感觉有点类似MyBatis, 会显得清爽很多, 只需定义一个抽象方法加上对应的注解@Modifying和@Query(value="sql语句", nativeQuery=true)即可, 它还有一个好处, 不用让封装查询条件这种事情跑到service层去。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

更多精彩内容其他人还在看

SpringBoot中使用Ehcache的详细教程

EhCache 是一个纯 Java 的进程内缓存框架,具有快速、精干等特点,是 Hibernate 中默认的 CacheProvider。这篇文章主要介绍了SpringBoot中使用Ehcache的相关知识,需要的朋友可以参考下
收藏 0 赞 0 分享

在idea 中添加和删除模块Module操作

这篇文章主要介绍了在idea 中添加和删除模块Module操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
收藏 0 赞 0 分享

java spring整合junit操作(有详细的分析过程)

这篇文章主要介绍了java spring整合junit操作(有详细的分析过程),具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
收藏 0 赞 0 分享

详解JAVA 弱引用

这篇文章主要介绍了 JAVA 弱引用的相关资料,帮助大家更好的理解和学习java引用对象,感兴趣的朋友可以了解下
收藏 0 赞 0 分享

深入了解JAVA 虚引用

这篇文章主要介绍了JAVA 虚引用的相关资料,帮助大家更好的理解和学习JAVA,感兴趣的朋友可以了解下
收藏 0 赞 0 分享

详解JAVA 强引用

这篇文章主要介绍了JAVA 强引用的相关资料,帮助大家更好的理解和学习,感兴趣的朋友可以了解下
收藏 0 赞 0 分享

java中的按位与(&)用法说明

这篇文章主要介绍了java中的按位与(&)用法说明,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
收藏 0 赞 0 分享

深入了解JAVA 软引用

这篇文章主要介绍了JAVA 软引用的相关资料,帮助大家更好的理解和学习,感兴趣的朋友可以了解下
收藏 0 赞 0 分享

利用MyBatis实现条件查询的方法汇总

这篇文章主要给大家介绍了关于利用MyBatis实现条件查询的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者使用MyBatis具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
收藏 0 赞 0 分享

Intellij IDEA 与maven 版本不符 Unable to import maven project See logs for details: No implementation for org.apache.maven.model.path.PathTranslator was bound

这篇文章主要介绍了Intellij IDEA 与maven 版本不符 Unable to import maven project See logs for details: No implementation for org.apache.maven.model.path.Pa
收藏 0 赞 0 分享
查看更多