源码

在前面关于SimpleJpaRepository的文章[地址]中可以得知,SimpleJpaRepository间接实现了JpaSpecificationExecutor接口,本文就详细探究一下该接口。

JpaSpecificationExecutor的定义如下:

/**
* Interface to allow execution of {@link Specification}s based on the JPA criteria API.
*
* @author Oliver Gierke
* @author Christoph Strobl
*/
public interface JpaSpecificationExecutor<T> { /**
* Returns a single entity matching the given {@link Specification} or {@link Optional#empty()} if none found.
*
* @param spec can be {@literal null}.
* @return never {@literal null}.
* @throws org.springframework.dao.IncorrectResultSizeDataAccessException if more than one entity found.
*/
Optional<T> findOne(@Nullable Specification<T> spec); /**
* Returns all entities matching the given {@link Specification}.
*
* @param spec can be {@literal null}.
* @return never {@literal null}.
*/
List<T> findAll(@Nullable Specification<T> spec); /**
* Returns a {@link Page} of entities matching the given {@link Specification}.
*
* @param spec can be {@literal null}.
* @param pageable must not be {@literal null}.
* @return never {@literal null}.
*/
Page<T> findAll(@Nullable Specification<T> spec, Pageable pageable); /**
* Returns all entities matching the given {@link Specification} and {@link Sort}.
*
* @param spec can be {@literal null}.
* @param sort must not be {@literal null}.
* @return never {@literal null}.
*/
List<T> findAll(@Nullable Specification<T> spec, Sort sort); /**
* Returns the number of instances that the given {@link Specification} will return.
*
* @param spec the {@link Specification} to count instances for. Can be {@literal null}.
* @return the number of instances.
*/
long count(@Nullable Specification<T> spec);
}

解读:

上述接口提供了一个findOne方法以及三个接受不同参数的findAll方法,这几个方法接受Specification类型的参数

示例

在实际开发中,通常按如下示例中展示的方式使用JpaSpecificationExecutor接口

Repository层:

@Repository
public interface UserRepository extends JpaRepository<User, Integer>, JpaSpecificationExecutor<User> { }

Service层:

  public Page<User> getUsers(Integer id, Integer pageNum, Integer pageSize) {
Sort sort = Sort.by(Sort.Direction.DESC, "id");
Pageable pageable = PageRequest.of(pageNum, pageSize, sort); Specification<User> specification = (Specification<User>) (root, query, cb) -> {
Path<Integer> path = root.get("id");
return cb.lt(path, id);
};
return userRepository.findAll(specification, pageable);
}

解读:

此处Service调用了userRepository的findAll方法,参数为Specification的实例以及Pageable的实例,该findAll方法实质上是JpaSpecificationExecutor提供的findAll方法

Specification

从本文前面的描述得知,在调用JpaSpecificationExecutor接口提供的几个方法时需要构造Specification类型的参数。

在前面关于SimpleJpaRepository的文章[地址]中提到了构造Specification类型参数的方式:匿名内部类或者ExampleSpecification的实例,本小节来剖析一下Specification的细节。

类图

解读:

从类图可知,ByIdsSpecification、ExampleSpecification实现了Specification接口

进一步发掘,可以发现ByIdsSpecification、ExampleSpecification都是SimpleJpaRepository的内部类,如下图所示:

源码

Specification定义在包路径org.springframework.data.jpa.domain下,其定义如下:

/**
* Specification in the sense of Domain Driven Design.
*
* @author Oliver Gierke
* @author Thomas Darimont
* @author Krzysztof Rzymkowski
* @author Sebastian Staudt
* @author Mark Paluch
* @author Jens Schauder
*/
public interface Specification<T> extends Serializable { long serialVersionUID = 1L; /**
* Negates the given {@link Specification}.
*
* @param <T> the type of the {@link Root} the resulting {@literal Specification} operates on.
* @param spec can be {@literal null}.
* @return guaranteed to be not {@literal null}.
* @since 2.0
*/
static <T> Specification<T> not(@Nullable Specification<T> spec) { return spec == null //
? (root, query, builder) -> null //
: (root, query, builder) -> builder.not(spec.toPredicate(root, query, builder));
} /**
* Simple static factory method to add some syntactic sugar around a {@link Specification}.
*
* @param <T> the type of the {@link Root} the resulting {@literal Specification} operates on.
* @param spec can be {@literal null}.
* @return guaranteed to be not {@literal null}.
* @since 2.0
*/
static <T> Specification<T> where(@Nullable Specification<T> spec) {
return spec == null ? (root, query, builder) -> null : spec;
} /**
* ANDs the given {@link Specification} to the current one.
*
* @param other can be {@literal null}.
* @return The conjunction of the specifications
* @since 2.0
*/
default Specification<T> and(@Nullable Specification<T> other) {
return SpecificationComposition.composed(this, other, CriteriaBuilder::and);
} /**
* ORs the given specification to the current one.
*
* @param other can be {@literal null}.
* @return The disjunction of the specifications
* @since 2.0
*/
default Specification<T> or(@Nullable Specification<T> other) {
return SpecificationComposition.composed(this, other, CriteriaBuilder::or);
} /**
* 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);
}

解读:

其中只有toPredicate方法抽象方法,所以通过匿名内部类的形式构造Specification的实例时只需实现toPredicate方法即可。

Root、Path

Specification中toPredicate方法的的第一个参数为Root<T> root,前面示例的Service层在实现toPredicate方法时通过调用如下语句获得Path类型的变量

Path<Integer> path = root.get("id");

下图展示了Root、Path之间的关系:

解读:

从上图可知,Root接口间接继承了Path接口,前述调用语句中的get方法由Path接口定义

相关代码如下:

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

参加[官方Doc]

Spring Data JPA:解析JpaSpecificationExecutor & Specification的更多相关文章

  1. spring data jpa封装specification实现简单风格的动态查询

    github:https://github.com/peterowang/spring-data-jpa-demo 单一实体的动态查询: @Servicepublic class AdvancedUs ...

  2. Spring Data JPA教程, 第四部分: JPA Criteria Queries(未翻译)

    The third part of my Spring Data JPA tutorialdescribed how you can create custom queries by using qu ...

  3. Spring Data Jpa:分页、Specification、Criteria

    分页的主要接口与类 PagingAndSortingRepository 继承自 CrudRepository 接口,提供了排序以及分页查询能力,提供了两个方法 Iterable<T> f ...

  4. spring data jpa 全面解析(实践 + 源码分析)

    前言 本文将从示例.原理.应用3个方面介绍spring data jpa. 以下分析基于spring boot 2.0 + spring 5.0.4版本源码 概述 JPA是什么? JPA (Java ...

  5. Spring data jpa 实现简单动态查询的通用Specification方法

    本篇前提: SpringBoot中使用Spring Data Jpa 实现简单的动态查询的两种方法 这篇文章中的第二种方法 实现Specification 这块的方法 只适用于一个对象针对某一个固定字 ...

  6. 【spring boot 系列】spring data jpa 全面解析(实践 + 源码分析)

    前言 本文将从示例.原理.应用3个方面介绍spring data jpa. 以下分析基于spring boot 2.0 + spring 5.0.4版本源码 概述 JPA是什么? JPA (Java ...

  7. 使用Spring Data JPA的Specification构建数据库查询

    Spring Data JPA最为优秀的特性就是可以通过自定义方法名称生成查询来轻松创建查询SQL.Spring Data JPA提供了一个Repository编程模型,最简单的方式就是通过扩展Jpa ...

  8. Spring Data JPA:解析SimpleJpaRepository

    源码 SimpleJpaRepository的定义如下: /** * Default implementation of the {@link org.springframework.data.rep ...

  9. Spring Data JPA:解析CriteriaBuilder

    源码 在Spring Data JPA相关的文章[地址]中提到了有哪几种方式可以构建Specification的实例,该处需要借助CriteriaBuilder,回顾一下Specification中t ...

  10. Spring Data Jpa系列教程--------实体解析和关联关系

    Spring Data Jpa是基于HIbernate开发的,所以建立实体建的实体和映射关系需要好好好的去了解一下,本文有以下内容,实体管理器介绍,实体与数据库表的映射介绍,关联关系(一对多,多对多) ...

随机推荐

  1. aria2+uget+chrome

    1.安装aira2 sudo apt install aria2 2.安装及配置uget sudo apt install uget 编辑 -> 设置: 分类 -> 属性: 3.chrom ...

  2. Pytest单元测试框架之FixTure基本使用

    前言: 在单元测试框架中,主要分为:测试固件,测试用例,测试套件,测试执行及测试报告: 测试固件不难理解,也就是我们在执行测试用例前需要做的动作和测试执行后的需要做的事情: 比如在UI自动化测试中,我 ...

  3. 【剑指offer】28. 对称的二叉树

    剑指 Offer 28. 对称的二叉树 知识点:二叉树:递归 题目描述 请实现一个函数,用来判断一棵二叉树是不是对称的.如果一棵二叉树和它的镜像一样,那么它是对称的. 示例 输入:root = [1, ...

  4. 第十五篇 -- QListWidget与QToolButton(界面)

    效果图: 这还只是一个界面,并没有实现相应功能. 先看下这图的构成吧. 工具栏的就是将Action拖上去,这部分前面已经介绍过了,那就看下面这部分的构图. 1.左侧是一个工具箱(ToolBox)组件, ...

  5. GC相关问题

    为什么会有新生代? 如果不分代,所有对象全部在一个区域,每次GC都需要对全堆进行扫描,存在效率问题.分代后,可分别控制回收频率,并采用不同的回收算法,确保GC性能全局最优. 为什么新生代会采用复制算法 ...

  6. mysql中的with rollup得到group by的汇总信息

    使用mysql中的with rollup可以得到每个分组的汇总级别的数据: 表如下: CREATE TABLE `test3` (  `id` int(5) unsigned NOT NULL AUT ...

  7. 获取windows 操作系统下的硬件或操作系统信息等

    奇怪的工作,制作的是一款办公应用软件,领导却要求我统计用户计算机的物理信息,什么CPU的型号.核心数,什么内存信息等各种乱七八糟的用户信息.我想问,现在用户的信息就这么没有隐私性了么?想获取就获取传递 ...

  8. 跟你说个笑话,硕士毕业两年,月薪10k,天天面向CV编程

    "枯燥乏味的一天,又tm要开始了". 早上10:00,程序员毛毛带着路上买的早餐,打开24英寸的显示屏,去某论坛查一下昨天没有解决的bug. 9 个小时增删改查.搬砖写代码的一天又 ...

  9. Android面试中多说这么一句话,薪水直接涨5k

    小鱼同学最近很难受,明明获得了人人羡慕的大厂Offer,走在路上都能被熟人祝贺,学弟学妹争着抢着求他进行经验分享. 但有件事一直让他很介意.其实这件事起因很简单,是关于这份Offer的薪资问题,面试的 ...

  10. netty系列之:使用UDP协议

    目录 简介 UDP协议 String和ByteBuf的转换 构建DatagramPacket 启动客户端和服务器 总结 简介 在之前的系列文章中,我们到了使用netty做聊天服务器,聊天服务器使用的S ...