源码

在前面关于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. Python基础之函数的闭包与装饰器的介绍

    1.闭包的概念: 如果在一个函数中,定义了另外一个函数,并且那个函数使用了外面函数的变量,并且外面那个函数返回了里面这个函数的引用,那么称为里面的这个函数为闭包. 2.话不多说,以demo示例: de ...

  2. python3执行.sql文件

    这个脚本主要是遍历执行文件夹下的sql文件,但是没有辨别文件的格式,所以文件夹下只能够放.sql文件,否则会报错哈. 我的sql文件夹与执行的文件平级,所以dir_path就是sql,大家依照自己的路 ...

  3. DNS服务器安全---通过ipset对DNS异常解析流量的源IP地址进行管控

    ipset介绍 ipset是iptables的扩展,它允许你创建 匹配整个地址集合的规则.而不像普通的iptables链只能单IP匹配, ip集合存储在带索引的数据结构中,这种结构即时集合比较大也可以 ...

  4. DRF使用JWT进行用户认证

    1. 首先需要安装第三方依赖包 pip install djangorestframework-jwt 2. 在Django的settings文件中 配置全局的JWT认证类 REST_FRAMEWOR ...

  5. Python自动化测试面试题-经验篇

    目录 Python自动化测试面试题-经验篇 Python自动化测试面试题-用例设计篇 Python自动化测试面试题-Linux篇 Python自动化测试面试题-MySQL篇 Python自动化测试面试 ...

  6. Ubuntu Server连接Wi-Fi

    本文将介绍Ubuntu Server如何通过命令行使用wpa_supplicant连接Wi-Fi 环境 Ubuntu Server 20.04(64位) wpasupplicant 配置 1. 安装 ...

  7. 计算距离2020年圣诞节还有x天x时x分x秒

    //计算两者相差毫秒数 //创建当前时间和圣诞节时间的Date对象 var d1=new Date(); var d2=new Date('2020/12/25'); //计算相差的毫秒 var d= ...

  8. 在阿里云上单机部署k8s1.18

    系统:CentOS Linux release 8.1.1911 配置主机名 [root@iZwz9e3t4tj14jzewdtvj8Z ~]# hostnamectl set-hostname la ...

  9. 启动或重启Oracle数据以及监听

    (以下均为命令行形式) 1.切换到oracle数据库用户: su - oracle 2.查看数据库的监听状态: lsnrctl status 3.停止监听: lsnrctl stop 4.登陆到ora ...

  10. 管理员权限的窗口,收不到WM_COPYDATA

    windows用户界面特权隔离 一个运行在较低特权等级的应用程序的行为就受到了诸多限制,它不可以: 验证由较高特权等级进程创建的窗口句柄 通过调用SendMessage和PostMessage向由较高 ...