Spring Data JPA系列JpaSpecificationExecutor用法详解

 更新时间:2022年09月28日 15:47:37   作者:AKone  
这篇文章主要为大家介绍了Spring Data JPA系列JpaSpecificationExecutor用法详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

在上一篇文章中,我们介绍了QueryByExampleExecutor动态查询的方法,那么今天我们来学习JpaSpecificationExecutor的详细用法。

1、JpaSpecificationExecutor用法

我们来创建实体类,第一步:创建User类和UserAddress类

// User类
@Data
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Builder
@ToString(exclude = "address")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;
    private String name;
    private String email;
    @Enumerated(value = EnumType.STRING)
    private SexEnum sex;
    private Integer age;
    private LocalDateTime createTime;
    private LocalDateTime updateTime;
    @OneToMany(mappedBy = "user",fetch = FetchType.EAGER)
    private List<UserAddress> address;
}
// Address类
@Entity
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ToString(exclude = "user")
public class UserAddress {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String address;
    @ManyToOne(cascade = CascadeType.ALL)
    private User user;
}
// 性别枚举类
public enum SexEnum {
    BOY,
    GIRL
}

第二步:创建UserRepo ,我们继承JpaSpecificationExecutor接口

public interface UserRepo extends JpaSpecificationExecutor<User> {
}

第三步:测试,构造查询条件

  • name模糊查询
  • sex精准查询
  • age范围查询
  • address的in查询
    @Test
    public void test02(){
        User userQuery = User.builder()
                .name("jack")
                .email("123456@126.com")
                .sex(SexEnum.BOY)
                .age(20)
                .address(Lists.newArrayList(UserAddress.builder().address("shanghai").build()))
                .build();
        List<User> userList = userRepo.findAll(new Specification<User>() {
            @Override
            public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                List<Predicate> predicateList = new ArrayList<>();
                // name模糊查询
                if(StringUtils.isNotBlank(userQuery.getName())) {
                    predicateList.add(cb.like(root.get("name"),userQuery.getName()));
                }
                // sex精准查询
                if(userQuery.getSex()!=null) {
                    predicateList.add(cb.equal(root.get("sex"),userQuery.getSex()));
                }
                // age范围查询
                if(userQuery.getAge()!=null){
                    predicateList.add(cb.greaterThanOrEqualTo(root.get("age"),userQuery.getAge()));
                }
                // 关联查询
                if(!ObjectUtils.isEmpty(userQuery.getAddress())) {
                    predicateList.add(cb.in(root.join("address").get("address")).value(userQuery.getAddress().stream().map(a->a.getAddress()).collect(Collectors.toList())));
                }
                return query.where(predicateList.toArray(new Predicate[predicateList.size()])).getRestriction();
            }
        });
        System.out.println(userList);
    }

SQL执行结果如下:

select user0_.id as id1_4_, user0_.age as age2_4_, user0_.create_time as create_t3_4_, user0_.email as email4_4_, user0_.name as name5_4_, user0_.sex as sex6_4_, user0_.update_time as update_t7_4_ from user user0_ inner join user_address address1_ on user0_.id=address1_.user_id where (user0_.name like ?) and user0_.sex=? and user0_.age>=20 and (address1_.address in (?))

2、JpaSpecificationExecutor语法详解

先看源码:

public interface JpaSpecificationExecutor<T> {
   Optional<T> findOne(@Nullable Specification<T> spec);
   List<T> findAll(@Nullable Specification<T> spec);
   Page<T> findAll(@Nullable Specification<T> spec, Pageable pageable);
   List<T> findAll(@Nullable Specification<T> spec, Sort sort);
   long count(@Nullable Specification<T> spec);
   boolean exists(Specification<T> spec);
}
  • findOne(@Nullable Specification spec):根据Specification 条件查询单个对象
  • findAll(@Nullable Specification spec):根据Specification 条件, 查询List结果
  • findAll(@Nullable Specification spec, Pageable pageable):根据Specification 条件, 分页查询
  • findAll(@Nullable Specification spec, Sort sort):根据Specification 条件,带排序的查询结果
  • count(@Nullable Specification spec): 根据Specification 条件,查询数量
  • exists(Specification spec):根据Specification 条件,查询是否存在

2.1 Specification 接口

我们主要来看一下需要实现的方法:toPredicate(xx,xx,xx)

@Nullable
Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder);

调试代码

我们可以分别看到Root的实现类是RootImpl,CriteriaQuery的实现类是CriteriaQueryImpl,CriteriaBuilder的实现类是CriteriaBuilderImpl。这三个实现类都是由Hibernate实现,也就是说JpaSepcificationExecutor封装了原本需要我们直接操作Hibernate中Criteria的API。

2.2 Root< User >root

解释:这个root就相当于查询和操作的实体对象的根,我们就可以通过Path get(xx)的方法,来获取我们想要操作的字段。

<Y> Path<Y> get(String attributeName);

例如:获取User实体类中的name字段

predicateList.add(cb.like(root.get("name"),userQuery.getName()));

2.3 CriteriaQuery<?> query

这是一个Specific的顶层查询对象,它包含着查询的各个部分,比如select、from、where、group by 、Order by、distinct等。提供查询Root的方法,我们来看一下源码:

我们可以在上面的案例中看到query的用法:

return query.where(predicateList.toArray(new Predicate[predicateList.size()])).getRestriction();

我们可以再加一个groupBy的例子看看,如下所示:可以链式拼接

return query.where(predicateList.toArray(new Predicate[predicateList.size()])).groupBy(root.get("age")).getRestriction();

执行的SQL如下所示:

2.4 CriteriaBuilder cb

CriteriaBuilder是用来构建CritiaQuery的构建对象,其实就相当于条件或者条件组合,并以Predicate的形式返回,基本提供了所有常用的方法。

通过源码我们可以看到CriteriaBuilder 提供了and、any等用来查询条件的组合;还提供了between、equal、exist等用来做查询条件的查询。

例如:equal

predicateList.add(cb.equal(root.get("sex"),userQuery.getSex()));

例如:like

predicateList.add(cb.like(root.get("name"),userQuery.getName()));

例如:greaterThanEqualTo

predicateList.add(cb.greaterThanOrEqualTo(root.get("age"),userQuery.getAge()));

解释: 我们利用equal、like、greaterThanEqualTo 可以返回Predicate,而Predicate又可以组合起来,就构成了复杂的查询条件,完全满足日常开发使用。

以上就是Spring Data JPA系列JpaSpecificationExecutor用法详解的详细内容,更多关于Spring Data JPA JpaSpecificationExecutor的资料请关注脚本之家其它相关文章!

相关文章

  • java string 转date方法如何实现

    java string 转date方法如何实现

    在开发应用中经常会使用到java string 转date这种不是很常见的做法,本文将以此问题提供详细解决方案,需要了解的朋友可以参考下
    2012-11-11
  • Jax-rs规范REST接口文件上传代码实例

    Jax-rs规范REST接口文件上传代码实例

    这篇文章主要介绍了Jax-rs规范REST接口文件上传代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-09-09
  • 关于SpringBoot获取IOC容器中注入的Bean(推荐)

    关于SpringBoot获取IOC容器中注入的Bean(推荐)

    本文通过实例代码给大家详解了springboot获取ioc容器中注入的bean问题,非常不错,具有一定的参考借鉴价值,需要的朋友参考下吧
    2018-05-05
  • 关于Java中static关键字的用法

    关于Java中static关键字的用法

    这篇文章主要介绍了关于Java中static关键字的用法,static:意为静态的,在 Java 里面作为静态修饰符,可以理解为全局的意思,static 不仅可以修饰成员变量,成员方法,还可以修饰代码块,需要的朋友可以参考下
    2023-08-08
  • Java使用Freemarker页面静态化生成的实现

    Java使用Freemarker页面静态化生成的实现

    这篇文章主要介绍了Java使用Freemarker页面静态化生成的实现,页面静态化是将原来的动态网页改为通过静态化技术生成的静态网页,FreeMarker 是一个用 Java 语言编写的模板引擎,它基于模板来生成文本输,更多相关内容需要的小伙伴可以参考一下
    2022-06-06
  • WeakHashMap的使用方法详解

    WeakHashMap的使用方法详解

    这篇文章主要介绍了WeakHashMap的使用方法详解的相关资料,希望通过本文能帮助到大家,让大家理解掌握这部分内容,需要的朋友可以参考下
    2017-10-10
  • IDEA 隐藏DEBUG日志的解决方法

    IDEA 隐藏DEBUG日志的解决方法

    IDEA 打印太多的DEBUG日志,看起来很烦,有没有办法隐藏日志,网上找了一圈,没有谁写的靠谱的,下面小编给大家分享下IDEA 如何隐藏DEBUG日志,需要的朋友可以参考下
    2022-09-09
  • Java 超详细图解集合框架的数据结构

    Java 超详细图解集合框架的数据结构

    什么是集合框架呢?集合框架是为表示和操作集合而规定的一种统一的标准的体系结构。最简单的集合如数组、列表和队列等,任何集合框架一般包含:对外的接口、接口的实现和对集合运算的算法
    2022-04-04
  • Java Git Commit Message使用规范

    Java Git Commit Message使用规范

    这篇文章主要介绍了Java Git Commit Message使用规范,文章围绕主题展开详细的内容介绍,具有一定的参考价值,感兴趣的小伙伴可以参考一下,希望对你的学习有所帮助
    2022-08-08
  • 详解Spring不同数据库异常如何抽象的

    详解Spring不同数据库异常如何抽象的

    根据spring-jdbc中的定义,所有的数据操作异常都会转换为 DataAccessException,下面这篇文章主要给大家介绍了关于Spring不同数据库异常如何抽象的相关资料,需要的朋友可以参考下
    2021-09-09

最新评论