使用Spring Data Jpa的CriteriaQuery一个陷阱

 更新时间:2020年11月12日 08:35:38   作者:钟潘  
使用Spring Data Jpa的CriteriaQuery进行动态条件查询时,可能会遇到一个陷阱,当条件为空时,查询不到任何结果,并不是期望的返回所有结果。这是为什么呢?

使用Spring Data Jpa的CriteriaQuery进行动态条件查询时,可能会遇到一个陷阱,当条件为空时,查询不到任何结果,并不是期望的返回所有结果。这是为什么呢?

例如下述代码,当predicates为空时,返回结果总是为空。

public Page<VmhostWithRelationPO> listVmhostSpecWithRelationByPage(String name) {
 Specification<VmhostWithRelationPO> spec = (root, cq, cb) -> {
 root.join("user", JoinType.LEFT);
 root.join("tenant", JoinType.LEFT);
 List<javax.persistence.criteria.Predicate> predicates = new ArrayList<>();
 ......
 return cb.or(predicates.toArray(new javax.persistence.criteria.Predicate[0]));
 };
 PageRequest pagable = PageRequest.of(0, 5);
 Page<VmhostWithRelationPO> page = vmhostSpecWithRelationDao.findAll(spec, pagable);
 return page;
}

看下or的注释就明白了,因为空条件总是为false,而and的空条件总是为true。所以,如果最后是and就没有问题,只有or的时候有问题。

public interface CriteriaBuilder {

 /**
  * Create a conjunction of the given restriction predicates.
  * A conjunction of zero predicates is true.
  * @param restrictions zero or more restriction predicates
  * @return and predicate
  */
 Predicate and(Predicate... restrictions);


 /**
  * Create a disjunction of the given restriction predicates.
  * A disjunction of zero predicates is false.
  * @param restrictions zero or more restriction predicates
  * @return or predicate
  */
 Predicate or(Predicate... restrictions);
}

所以正确的写法应该这样:

public Page<VmhostWithRelationPO> listVmhostSpecWithRelationByPage(String name) {
 Specification<VmhostWithRelationPO> spec = (root, cq, cb) -> {
  root.join("user", JoinType.LEFT);
  root.join("tenant", JoinType.LEFT);
  List<javax.persistence.criteria.Predicate> predicates = new ArrayList<>();
  ......
  return predicates.isEmpty() ? cb.conjunction() : cb.or(predicates.toArray(new javax.persistence.criteria.Predicate[0]));
 };
 PageRequest pagable = PageRequest.of(0, 5);
 Page<VmhostWithRelationPO> page = vmhostSpecWithRelationDao.findAll(spec, pagable);
 return page;
 }

如果条件为空则返回一个空conjunction,也就是空的and,总是为true。

公司项目的代码中常见这种写法:

public Page<VmhostWithRelationPO> listVmhostSpecWithRelationByPage(String name) {
 Specification<VmhostWithRelationPO> spec = (root, cq, cb) -> {
 root.join("user", JoinType.LEFT);
 root.join("tenant", JoinType.LEFT);
 List<javax.persistence.criteria.Predicate> predicates = new ArrayList<>();
 ......
 if (predicates.isEmpty()) {
  cq.where();
 } else {
  cq.where(cb.or(predicates.toArray(new javax.persistence.criteria.Predicate[0])));
 }
 return cq.getRestriction();
 };
 PageRequest pagable = PageRequest.of(0, 5);
 Page<VmhostWithRelationPO> page = vmhostSpecWithRelationDao.findAll(spec, pagable);
 return page;
}

也能正常工作,但是其实没有必要在toPredicate方法中调用where,toPredicate只需要返回条件,外层会调用where。

public interface Specification<T> extends Serializable {


 /**
  * Creates a WHERE clause for a query of the referenced entity in form of a {@link Predicate} for the given
  * {@link Root} and {@link CriteriaQuery}.
  *
  * @param root must not be {@literal null}.
  * @param query must not be {@literal null}.
  * @param criteriaBuilder must not be {@literal null}.
  * @return a {@link Predicate}, may be {@literal null}.
  */
 @Nullable
 Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder);
}

本文作者: 钟潘
本文链接: http://zhongpan.tech/2020/07/20/035-a-trap-for-using-criteriaquery/

以上就是CriteriaQuery使用的一个陷阱的详细内容,更多关于CriteriaQuery 陷阱的资料请关注脚本之家其它相关文章!

相关文章

  • springboot 使用QQ邮箱发送邮件的操作方法

    springboot 使用QQ邮箱发送邮件的操作方法

    这篇文章主要介绍了springboot使用QQ邮箱发送邮件功能,本文通过实例图文相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-10-10
  • Java实现的打印螺旋矩阵算法示例

    Java实现的打印螺旋矩阵算法示例

    这篇文章主要介绍了Java实现的打印螺旋矩阵算法,结合完整实例形式详细分析了java打印螺旋矩阵的算法原理与实现技巧,需要的朋友可以参考下
    2019-10-10
  • maven插件spring-boot-starter-tomcat的使用方式

    maven插件spring-boot-starter-tomcat的使用方式

    这篇文章主要介绍了maven插件spring-boot-starter-tomcat的使用方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-07-07
  • 使用Spring Batch实现批处理任务的详细教程

    使用Spring Batch实现批处理任务的详细教程

    在企业级应用中,批处理任务是不可或缺的一部分,它们通常用于处理大量数据,如数据迁移、数据清洗、生成报告等,Spring Batch是Spring框架的一部分,本文将介绍如何使用Spring Batch与SpringBoot结合,构建和管理批处理任务,需要的朋友可以参考下
    2024-06-06
  • Java8新特性:函数式编程

    Java8新特性:函数式编程

    Java8最新引入函数式编程概念,该项技术可以大大提升编码效率,本文会对涉及的对象等进行两种方法的对比,对新技术更直白的看到变化,更方便学习
    2021-06-06
  • Java报错:Java.io.FileNotFoundException解决方法

    Java报错:Java.io.FileNotFoundException解决方法

    这篇文章主要介绍了Java.io.FileNotFoundException的产生原因和解决方法,造成这个报错的原因可能有文件路径错误、文件被删除或移动和权限问题,文中将解决的办法介绍的非常详细,需要的朋友可以参考下
    2024-12-12
  • Java锁之自旋锁详解

    Java锁之自旋锁详解

    这篇文章主要介绍了Java锁之自旋锁详解,本文是系列文章的第一篇,请持续关注脚本之家java栏目,需要的朋友可以参考下
    2014-09-09
  • 关于批量插入或更新数据(MyBatis-plus框架)

    关于批量插入或更新数据(MyBatis-plus框架)

    这篇文章主要介绍了关于批量插入或更新数据(MyBatis-plus框架),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-09-09
  • 如何区分JAVA中的throws和throw

    如何区分JAVA中的throws和throw

    这篇文章主要介绍了如何区分JAVA中的throws和throw,文中讲解十分详细,代码帮助大家更好的理解和学习,感兴趣的朋友可以了解下
    2020-06-06
  • Java发送邮箱验证码、session校验功能

    Java发送邮箱验证码、session校验功能

    本篇主要描述“发送邮箱验证码、session校验”相关前(html\js)后(java)台代码,业务逻辑示例,需要的朋友可以参考下
    2018-02-02

最新评论