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

JPA实现复杂条件分页查询的更多相关文章

  1. springboot jpa mongodb 多条件分页查询

    public Page<Recorded> getRecordeds(Integer page, Integer size, Recorded recorded) { if (page&l ...

  2. asp.net mvc多条件+分页查询解决方案

    开发环境vs2010 css:bootstrap js:jquery bootstrap paginator 原先只是想做个mvc的分页,但是一般的数据展现都需要检索条件,而且是多个条件,所以就变成了 ...

  3. 【java】spring-data-jpa 集成hibernate实现多条件分页查询

    初次接触spring-data-jpa,实现多条件分页查询. 基础环境 Spring Boot+spring-data-jpa+hibernate+mysql 1.接口 要继承这个接口,这个接口提供了 ...

  4. thinkphp 带条件分页查询

    thinkphp 带条件分页查询:form表单传值时候,method='get'. 用 get 传值

  5. 项目一:第四天 1、快递员的条件分页查询-noSession,条件查询 2、快递员删除(逻辑删除) 3、基于Apache POI实现批量导入区域数据 a)Jquery OCUpload上传文件插件使用 b)Apache POI读取excel文件数据

    1. 快递员的条件分页查询-noSession,条件查询 2. 快递员删除(逻辑删除) 3. 基于Apache POI实现批量导入区域数据 a) Jquery OCUpload上传文件插件使用 b) ...

  6. ASPNETCOREAPI 跨域处理 SQL 语句拼接 多条件分页查询 ASPNET CORE 核心 通过依赖注入(注入服务)

    ASPNETCOREAPI 跨域处理 AspNetCoreApi 跨域处理 如果咱们有处理过MV5 跨域问题这个问题也不大. (1)为什么会出现跨域问题:  浏览器安全限制了前端脚本跨站点的访问资源, ...

  7. JPA分页查询与条件分页查询

    情有独钟的JPA 平时在写一些小项目时,比较喜欢引用 Spring Data Jpa,其实还是图他写代码快~在日常的开发工作中,分页列表查询基本是随处可见,下面一起看一下如何使用 jpa 进行多条件查 ...

  8. jpa自定义条件分页查询

    主要依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>sp ...

  9. 【spring data jpa】带有条件的查询后分页和不带条件查询后分页实现

    一.不带有动态条件的查询 分页的实现 实例代码: controller:返回的是Page<>对象 @Controller @RequestMapping(value = "/eg ...

随机推荐

  1. 软件开发架构介绍||OSI七层协议之物理层、数据链路层、网络层、传输层(mac地址、ip协议、断开协议、tcp协议之三次握手四次挥手)

    一.网络编程 软件开发架构 C/S架构 C:客户端 想体验服务的时候才会去找服务端体验服务 S:服务端   24小时不间断的提供服务,即时监听,随时待命 B/S架构 B:浏览器    想体验服务的时候 ...

  2. 【Teradata】TD Unicode编码格式下varchar定义测试

    如下测试表,每个字段字符编码格式均为Unicode. 1.varchar(1)可以存储1个汉字,也只能存储1个ASCII字符. --创建表nc_test,每个字段编码格式均设定为Unicode[使用S ...

  3. scrapy-redis 分布式爬虫

    为什么要学? Scrapy_redis在scrapy的基础上实现了更多,更强大的功能. 有哪些功能体现? request去重.爬虫持久化.实现分布式爬虫.断点续爬(带爬取的request存在redis ...

  4. Ambari 常用的 REST API 介绍

    源码文档路径:ambari\ambari-server\docs\api\v1 swagger风格api文档:https://www.cnblogs.com/felixzh/p/10694724.ht ...

  5. kettle 备注

    1. 基本组成 1.1 spoon: 一个可视化的工具,用于编辑kettle ETL的任务脚本 1.2 span: 用以命令行方式执行spoon的转换 1.3 kitchen: 用以命令行方式执行sp ...

  6. 再谈AbstractQueuedSynchronizer3:基于AbstractQueuedSynchronizer的并发类实现

    公平模式ReentrantLock实现原理 前面的文章研究了AbstractQueuedSynchronizer的独占锁和共享锁,有了前两篇文章的基础,就可以乘胜追击,看一下基于AbstractQue ...

  7. Java数据结构和算法 - 堆

    堆的介绍 Q: 什么是堆? A: 这里的“堆”是指一种特殊的二叉树,不要和Java.C/C++等编程语言里的“堆”混淆,后者指的是程序员用new能得到的计算机内存的可用部分 A: 堆是有如下特点的二叉 ...

  8. Python开发:Python2和Python3的共存和切换使用

    从python2到python3,这两个版本可以说是从语法.编码等多个方面上都有很大的差别.为了不带入过多的累赘,Python 3.0在设计的时候没有考虑向下相容,也就是说许多针对早期Python2版 ...

  9. C# 《编写高质量代码改善建议》整理&笔记 --(五)类型设计

    1.区分接口和抽象类的应用场合 区别: ①接口支持多继承,抽象类则不能. ②接口可以包含方法,属性,索引器,事件的签名,但不能有实现,抽象类则可以. ③接口在增加新方法后,所有的继承者都必须重构,否则 ...

  10. 从零开始学习PYTHON3讲义(十)自己做一个“电子记事本”

    <从零开始PYTHON3>第十讲 截至上一讲,我们已经完成了Python语言的基本部分.我们用了三讲来讨论Python语言的控制结构,用了两讲来介绍Python的基本数据类型.可以说仅就语 ...