Spring Data JPA:解析JpaSpecificationExecutor & Specification
源码
在前面关于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的更多相关文章
- spring data jpa封装specification实现简单风格的动态查询
github:https://github.com/peterowang/spring-data-jpa-demo 单一实体的动态查询: @Servicepublic class AdvancedUs ...
- Spring Data JPA教程, 第四部分: JPA Criteria Queries(未翻译)
The third part of my Spring Data JPA tutorialdescribed how you can create custom queries by using qu ...
- Spring Data Jpa:分页、Specification、Criteria
分页的主要接口与类 PagingAndSortingRepository 继承自 CrudRepository 接口,提供了排序以及分页查询能力,提供了两个方法 Iterable<T> f ...
- spring data jpa 全面解析(实践 + 源码分析)
前言 本文将从示例.原理.应用3个方面介绍spring data jpa. 以下分析基于spring boot 2.0 + spring 5.0.4版本源码 概述 JPA是什么? JPA (Java ...
- Spring data jpa 实现简单动态查询的通用Specification方法
本篇前提: SpringBoot中使用Spring Data Jpa 实现简单的动态查询的两种方法 这篇文章中的第二种方法 实现Specification 这块的方法 只适用于一个对象针对某一个固定字 ...
- 【spring boot 系列】spring data jpa 全面解析(实践 + 源码分析)
前言 本文将从示例.原理.应用3个方面介绍spring data jpa. 以下分析基于spring boot 2.0 + spring 5.0.4版本源码 概述 JPA是什么? JPA (Java ...
- 使用Spring Data JPA的Specification构建数据库查询
Spring Data JPA最为优秀的特性就是可以通过自定义方法名称生成查询来轻松创建查询SQL.Spring Data JPA提供了一个Repository编程模型,最简单的方式就是通过扩展Jpa ...
- Spring Data JPA:解析SimpleJpaRepository
源码 SimpleJpaRepository的定义如下: /** * Default implementation of the {@link org.springframework.data.rep ...
- Spring Data JPA:解析CriteriaBuilder
源码 在Spring Data JPA相关的文章[地址]中提到了有哪几种方式可以构建Specification的实例,该处需要借助CriteriaBuilder,回顾一下Specification中t ...
- Spring Data Jpa系列教程--------实体解析和关联关系
Spring Data Jpa是基于HIbernate开发的,所以建立实体建的实体和映射关系需要好好好的去了解一下,本文有以下内容,实体管理器介绍,实体与数据库表的映射介绍,关联关系(一对多,多对多) ...
随机推荐
- ssh保持长连接的方式
方法有以下三种:1.修改server端的etc/ssh/sshd_configClientAliveInterval 60 #server每隔60秒发送一次请求给client,然后client响应,从 ...
- 记一次.Net5接入支付宝SDK的小插曲
由于业务需求,在项目里面要接入支付宝的支付功能,于是在github上找到了支付宝的官方sdk:https://hub.fastgit.org/alipay/alipay-easysdk 先说问题: 在 ...
- 42 张图带你撸完 MySQL 优化
Hey guys,这里是程序员cxuan,欢迎你阅读我最新一期的文章,这篇文章是 MySQL 调优的汇总版,我加了一下日常开发过程中的调优经验,希望对各位小伙伴们有所帮助.下面开始正文. 一般传统互联 ...
- OpenFaaS实战之三:Java函数
欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...
- 【洛谷P1962 斐波那契数列】矩阵快速幂+数学推导
来提供两个正确的做法: 斐波那契数列双倍项的做法(附加证明) 矩阵快速幂 一.双倍项做法 在偶然之中,在百度中翻到了有关于斐波那契数列的词条(传送门),那么我们可以发现一个这个规律$ \frac{F_ ...
- 数据库开发之ETL概念
原文链接:https://blog.csdn.net/jianzhang11/article/details/104240047/ ETL基础概念 - 背景随着企业的发展,各业务线.产品线.部门都会承 ...
- Win10离线安装.net3.5
起因 工作原因需要安装vs2008,但是依赖.net3.5,寻找可以离线安装的版本 尝试 下载.net framework sp1完整包 dotnetfx35.exe 可选下载 语言包 dotnetf ...
- friend靶机
仅供个人娱乐 靶机信息 https://www.vulnhub.com/entry/me-and-my-girlfriend-1,409/ 一.主机探测 二.信息收集 访问一下web站点,提示只能从本 ...
- 图解 HTTP 连接管理
熟悉我的小伙伴都知道,我之前肝了本<HTTP 核心总结>的 PDF,这本 PDF 是取自我 HTTP 系列文章的汇总,然而我写的 HTTP 相关内容都是一年前了,我回头看了一下这本 PDF ...
- Mysql读写锁保姆级图文教程
摘要:读锁会阻塞写,但是不会阻塞读,而写锁会把杜希俄都阻塞. 本文分享自华为云社区<Mysql保姆级读写锁图文教程丨[绽放吧!数据库]>,作者:Code皮皮虾 . 准备 创建mylock表 ...