Spring data jpa的使用与详解(复杂动态查询及分页,排序)

一、 使用Specification实现复杂查询

(1) 什么是Specification

Specification是springDateJpa中的一个接口,他是用于当jpa的一些基本CRUD操作的扩展,可以把他理解成一个spring jpa的复杂查询接口。其次我们需要了解Criteria 查询,这是是一种类型安全和更面向对象的查询。而Spring Data JPA支持JPA2.0的Criteria查询,相应的接口是JpaSpecificationExecutor。

而JpaSpecificationExecutor这个接口基本是围绕着Specification接口来定义的,Specification接口中只定义了如下一个方法:

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

Criteria查询基本概念:

Criteria 查询是以元模型的概念为基础的,元模型是为具体持久化单元的受管实体定义的,这些实体可以是实体类,嵌入类或者映射的父类。

CriteriaQuery接口:

代表一个specific的顶层查询对象,它包含着查询的各个部分,比如:select 、from、where、group by、order by等注意:CriteriaQuery对象只对实体类型或嵌入式类型的Criteria查询起作用。

Root:

代表Criteria查询的根对象,Criteria查询的查询根定义了实体类型,能为将来导航获得想要的结果,它与SQL查询中的FROM子句类似。
Root实例是类型化的,且定义了查询的FROM子句中能够出现的类型。root代表查询的实体类,query可以从中得到root对象,告诉jpa查询哪一个实体类,还可以添加查询条件,还可以结合EntityManager对象 得到最终查询的 TypedQuery对象。

CriteriaBuilder接口:

用来构建CritiaQuery的构建器对象Predicate:一个简单或复杂的谓词类型,其实就相当于条件或者是条件组合。 可通过 EntityManager.getCriteriaBuilder 而得。

二、使用Specification进行复杂的动态查询

maven的依赖继续使用上一章的就可以,这里修改一下实体类和controller层。

请求实体类:

@Data
public class AccountRequest {

  //从第几页开始
  private Integer page;

  //每一页查询多少
  private Integer limit;

  private String id;

  private String name;

  private String pwd;

  private String email;

  private Integer[] types;

}

实体类:

@Data
@Entity
@Table(name = "account")
@ToString
@EntityListeners(AuditingEntityListener.class)
public class Account {

  @Id
  @GenericGenerator(name = "idGenerator", strategy = "uuid")
  @GeneratedValue(generator = "idGenerator")
  private String id;

  @Column(name = "username", unique = true, nullable = false, length = 64)
  private String username;

  @Column(name = "password", nullable = false, length = 64)
  private String password;

  @Column(name = "email", length = 64)
  private String email;

  @Column(name = "type")
  private Short type;

  @CreatedDate
  @Column(name = "create_time", nullable = false)
  private LocalDateTime createTime;

}

Repository层:

public interface AccountRepository extends JpaRepository<Account,String>, JpaSpecificationExecutor<Account> {}

controller层(还是直接略过service层)

@Autowired
  private AccountRepository repository;

  @PostMapping("/get")
  public List<Account> get(@RequestBody AccountRequest request){
    Specification<Account> specification = new Specification<Account>() {

      @Override
      public Predicate toPredicate(Root<Account> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder builder) {
        //所有的断言 及条件
        List<Predicate> predicates = new ArrayList<>();
        //精确匹配id pwd
        if (request.getId() != null) {
          predicates.add(builder.equal(root.get("id"), request.getId()));
        }
        if (request.getPwd() != null) {
          predicates.add(builder.equal(root.get("password"), request.getPwd()));
        }
        //模糊搜索 name
        if (request.getName() != null && !request.getName().equals("")) {
          predicates.add(builder.like(root.get("username"), "%" + request.getName() + "%"));
        }
        if (request.getEmail() != null && !request.getEmail().equals("")) {
          predicates.add(builder.like(root.get("email"), "%" + request.getEmail() + "%"));
        }
        //in范围查询
        if (request.getTypes() != null) {
          CriteriaBuilder.In<Object> types = builder.in(root.get("type"));
          for (Integer type : request.getTypes()) {
            types = types.value(type);
          }
          predicates.add(types);
        }
        return builder.and(predicates.toArray(new Predicate[predicates.size()]));
      }
    };
    List<Account> accounts = repository.findAll(specification);

    return accounts;
  }

通过重写Specification的toPredicate的方法,这样一个复杂的动态sql查询就完成了,通过post请求直接就可以调用了。

三、分页及排序

@PostMapping("/page")
  public List<Account> getPage(@RequestBody AccountRequest request){

    Specification<Account> specification = new Specification<Account>() {
      @Override
      public Predicate toPredicate(Root<Account> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
        List<Predicate> predicates = new ArrayList<>();
        //do anything
        return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
      }
    };
    //表示通过createTime进行 ASC排序
    PageRequest page = new PageRequest(request.getPage() - 1, request.getLimit(), Sort.Direction.ASC, "createTime");
    Page<Account> pageInfo = repository.findAll(specification, page);

    return pageInfo.getContent();
  }

上面的代码是在经过复杂查询并进行分页与排序,通过PageRequest来构建分页排序的规则。传入起始页及每页的数量,还有排序的规则及以哪个属性排序。jpa中是以第0页开始的,所以传参的时候需要注意!

当然,如果你不需要进行复杂的查询也可以对数据进行分页及排序查询。

修改repository,使其继承PagingAndSortingRepository。

@Repository
public interface AccountRepository extends JpaRepository<Account,String>, JpaSpecificationExecutor<Account> , PagingAndSortingRepository<Account,String> {
  Page<Account> findByAge(int age, Pageable pageable);
}

使用时先创建pageable参数,然后传进去就可以了。

//显示第1页每页显示3条
PageRequest pr = new PageRequest(1,3);
//根据年龄进行查询
Page<Account> stus = accountPageRepository.findByAge(22,pr);

排序也是一样的,在repository中创建方法

List<Account> findByPwd(String pwd, Sort sort);

调用的时候传入sort对象

//设置排序方式为username降序
List<Account> accs = accountPageRepository.findByAge("123456",new Sort(Sort.Direction.DESC,"username"));
//设置排序以username和type进行升序
acc = accountPageRepository.findByAge("123456",new Sort(Sort.Direction.ASC,"username","type"));
//设置排序方式以name升序,以address降序
Sort sort = new Sort(new Sort.Order(Sort.Direction.ASC,"name"),new Sort.Order(Sort.Direction.DESC,"type"));
accs = accountPageRepository.findByAge("123456",sort);

到此这篇关于Spring data jpa的使用与详解(复杂动态查询及分页,排序)的文章就介绍到这了,更多相关Spring data jpa内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

时间: 2020-10-31

Spring Data JPA 简单查询--方法定义规则(详解)

一.常用规则速查 1 And 并且 2 Or   或 3 Is,Equals 等于 4 Between   两者之间 5 LessThan 小于 6 LessThanEqual   小于等于 7 GreaterThan 大于 8 GreaterThanEqual   大于等于 9 After 之后(时间) > 10 Before 之前(时间) < 11 IsNull 等于Null 12 IsNotNull,NotNull 不等于Null 13 Like 模糊查询.查询件中需要自己加 % 14

Spring Data JPA调用存储过程实例代码

JPA连接到数据库,调用存储过程,这样的需求很常见.本文就针对这一点,讲述如何使用spring Data JPA调用存储过程的方法. 1.存储过程 假设存储过程如下: CREATE OR REPLACE PACKAGE test_pkg AS PROCEDURE in_only_test (inParam1 IN VARCHAR2); PROCEDURE in_and_out_test (inParam1 IN VARCHAR2, outParam1 OUT VARCHAR2); END tes

spring data jpa使用详解(推荐)

使用Spring data JPA开发已经有一段时间了,这期间学习了一些东西,也遇到了一些问题,在这里和大家分享一下. 前言: Spring data简介: Spring Data是一个用于简化数据库访问,并支持云服务的开源框架.其主要目标是使得对数据的访问变得方便快捷,并支持map-reduce框架和云计算数据服务. Spring Data 包含多个子项目: Commons - 提供共享的基础框架,适合各个子项目使用,支持跨数据库持久化 JPA - 简化创建 JPA 数据访问层和跨存储的持久层

Spring Data JPA实现分页Pageable的实例代码

在JPA中提供了很方便的分页功能,那就是Pageable(org.springframework.data.domain.Pageable)以及它的实现类PageRequest(org.springframework.data.domain.PageRequest),详细的可以见示例代码. 1.改变CustomerRepository方法​ /** * 一个参数,匹配两个字段 * @param name2 * @Param pageable 分页参数 * @return * 这里Param的值和

详解Spring Data JPA动态条件查询的写法

我们在使用SpringData JPA框架时,进行条件查询,如果是固定条件的查询,我们可以使用符合框架规则的自定义方法以及@Query注解实现. 如果是查询条件是动态的,框架也提供了查询接口. JpaSpecificationExecutor 和其他接口使用方式一样,只需要在你的Dao接口继承即可(官网代码). public interface CustomerRepository extends CrudRepository<Customer, Long>, JpaSpecification

Spring Data JPA实现动态查询的两种方法

前言 一般在写业务接口的过程中,很有可能需要实现可以动态组合各种查询条件的接口.如果我们根据一种查询条件组合一个方法的做法来写,那么将会有大量方法存在,繁琐,维护起来相当困难.想要实现动态查询,其实就是要实现拼接SQL语句.无论实现如何复杂,基本都是包括select的字段,from或者join的表,where或者having的条件.在Spring Data JPA有两种方法可以实现查询条件的动态查询,两种方法都用到了Criteria API. Criteria API 这套API可用于构建对数据

Spring Data JPA进行数据分页与排序的方法

一.导读 如果一次性加载成千上万的列表数据,在网页上显示将十分的耗时,用户体验不好.所以处理较大数据查询结果展现的时候,分页查询是必不可少的.分页查询必然伴随着一定的排序规则,否则分页数据的状态很难控制,导致用户可能在不同的页看到同一条数据.那么,本文的主要内容就是给大家介绍一下,如何使用Spring Data JPA进行分页与排序. 二.实体定义 我们使用一个简单的实体定义:Article(文章) @Data @AllArgsConstructor @NoArgsConstructor @Bu

elasticsearch python 查询的两种方法

elasticsearch python 查询的两种方法,具体内容如下所述: from elasticsearch import Elasticsearch es = Elasticsearch res1 = es.search(index="2018-07-31", body={"query": {"match_all": {}}}) print(es1) {'_shards': {'failed': 0, 'skipped': 0, 'suc

MySql逗号拼接字符串查询的两种方法

下面两个函数的使用和FIND_IN_SET一样,使用时只需要把FIND_IN_SET换成FIND_PART_IN_SET或FIND_ALL_PART_IN_SET 例如某字段里是为1,2,3,4,5 使用方法: 第一种,传入1,3,6  可以查出来 select * from XXX where FIND_PART_IN_SET('1,3,6','1,2,3,4,5') 第二种,传入1,3,6  查不出来 select * from XXX where FIND_ALL_PART_IN_SET(

Matlab制作视频并转换成gif动态图的两种方法

一.第一个方法比较简单,就是使用movie(f)直接取生成AVI视频文件. %% f(t)-->f(4*t+12) 并且验证%% function Signal_change() tic%记录程序运行时间 figure n = 0; t = -2*pi:0.01:2*pi; y = sin(t);%周期为2*pi y_result = sin(4*t); plot(t,y,'b'); xlabel('t'); ylabel('Amplitude'); n = n+1; F(n) = getfra

Spring Data JPA实现动态条件与范围查询实例代码

Spring Data JPA为我们提供了Query With Example来实现动态条件查询,当查询条件为空的时候,我们不用做大量的条件判断.但是Query With Example却不支持范围查询(包括日期范围,数值范围查询),本文通过Specification实现了既支持动态条件查询又支持范围查询的方法. 1 实现方式 1.1 范围对象Range定义 import java.io.Serializable; public class Range<E> implements Serial

Spring Data JPA分页复合查询原理解析

Spring Data JPA是Spring Data家族的一部分,可以轻松实现基于JPA的存储库. 此模块处理对基于JPA的数据访问层的增强支持. 它使构建使用数据访问技术的Spring驱动应用程序变得更加容易. 在相当长的一段时间内,实现应用程序的数据访问层一直很麻烦. 必须编写太多样板代码来执行简单查询以及执行分页和审计. Spring Data JPA旨在通过减少实际需要的工作量来显著改善数据访问层的实现. 作为开发人员,您编写repository接口,包括自定义查找器方法,Spring

vue父组件向子组件动态传值的两种方法

在一些项目需求中需要父组件向子组件动态传值,比如我这里的需求是,父组件动态通过axios获取返回的图片url数组然后传给子组件,上传图片的子组件拿到该数组后进行遍历并展示图片 方法有两种, 方法一: props传值,这里注意一个问题,传过来的值需要用watch监听并赋值,否则这里获取到的是空数组   父组件: <uploadImg :width="200" :height="200" name="productImage" size=&qu

Spring Boot处理全局统一异常的两种方法与区别

前言 在后端发生异常或者是请求出错时,前端通常显示如下 Whitelabel Error Page This application has no explicit mapping for /error, so you are seeing this as a fallback. Fri Jun 07 15:38:07 CST 2019 There was an unexpected error (type=Not Found, status=404). No message available

使用Spring Data JPA的坑点记录总结

前言 Spring-data-jpa的基本介绍:JPA诞生的缘由是为了整合第三方ORM框架,建立一种标准的方式,百度百科说是JDK为了实现ORM的天下归一,目前也是在按照这个方向发展,但是还没能完全实现.在ORM框架中,Hibernate是一支很大的部队,使用很广泛,也很方便,能力也很强,同时Hibernate也是和JPA整合的比较良好,我们可以认为JPA是标准,事实上也是,JPA几乎都是接口,实现都是Hibernate在做,宏观上面看,在JPA的统一之下Hibernate很良好的运行. 最近在