正确使用Spring Data JPA规范
在优锐课的学习分享中探讨了关于,Spring Data JPA的创建主要是为了通过按方法名称生成查询来轻松创建查询。 但是,有时我们需要创建复杂的查询,而无法利用查询生成器。码了很多知识笔记分享给大家。
Spring Data JPA提供了一个存储库编程模型,该模型以每个受管域对象的接口开头。 定义这些接口有两个目的:首先,通过扩展JpaRepository,我们获得了一堆通用的CRUD方法,例如save,findAll,delete等。 其次,这将允许Spring Data JPA存储库基础结构扫描该接口的类路径并为其创建Spring Bean。 典型的存储库界面如下所示:
public interface CustomerRepository extends JpaRepository<Customer, Long> {
Customer findByEmailAddress(String emailAddress);
List<Customer> findByLastname(String lastname, Sort sort);
Page<Customer> findByFirstname(String firstname, Pageable pageable);
}
要创建复杂的查询,为什么要指定规格?
是的,可以使用Criteria API构建复杂的查询。 要了解为什么要使用规范,我们考虑一个简单的业务需求。 我们将使用Criteria API以及随后的规范来实现此要求。
这是用例:在客户生日那天,我们希望向所有长期客户发送优惠券。 我们如何检索一个匹配的?
我们有两个谓词:
LocalDate today = new LocalDate(); CriteriaBuilder builder = em.getCriteriaBuilder(); CriteriaQuery<Customer> query = builder.createQuery(Customer.class); Root<Customer> root = query.from(Customer.class); Predicate hasBirthday = builder.equal(root.get(Customer_.birthday), today); Predicate isLongTermCustomer = builder.lessThan(root.get(Customer_.createdAt), today.minusYears(2); query.where(builder.and(hasBirthday, isLongTermCustomer)); em.createQuery(query.select(root)).getResultList();
在上面的代码中,
- ·第一行创建了LocalDate以比较客户的生日和今天的日期。
- ·以下三行包含用于设置必要的JPA基础结构实例的样板代码。
- ·然后,在接下来的两行中,我们将构建谓词
- ·在最后两行中,一个用于连接两个谓词,最后一个用于执行查询。
此代码的主要问题在于谓词不易于外部化和重用,因为您需要先设置CriteriaBuilder,CriteriaQuery和Root。 另外,由于难以快速推断出代码的意图,因此代码的可读性很差。
规格
为了能够定义可重用谓词,我们引入了规范接口,该接口源自Eric Evans的《域驱动设计》一书中引入的概念。 它将规范定义为实体的谓词,这正是规范接口所代表的含义。 实际上,这仅包含一个方法:
public interface Specification<T> {
Predicate toPredicate(Root<T> root, CriteriaQuery query, CriteriaBuilder cb);
}
使用Java 8时,代码变得非常清晰易懂。
public CustomerSpecifications {
public static Specification<Customer> customerHasBirthday() {
return (root, query, cb) ->{
return cb.equal(root.get(Customer_.birthday), today);
};
}
public static Specification<Customer> isLongTermCustomer() {
return (root, query, cb) ->{
return cb.lessThan(root.get(Customer_.createdAt), new LocalDate.minusYears(2));
};
}
}
客户端现在可以执行以下操作:
customerRepository.findAll(hasBirthday()); customerRepository.findAll(isLongTermCustomer());
在这里,基本实现将为您准备CriteriaQuery,Root和CriteriaBuilder,应用由给定规范创建的谓词并执行查询。
我们只是创建了可以单独执行的可重用谓词。 我们可以结合使用这些单独的谓词来满足我们的业务需求。 我们有一个帮助程序类规范,它提供了(和)和(或)方法来连接原子规范。
customerRepository.findAll(where(customerHasBirthday()).and(isLongTermCustomer()));
与仅使用JPA Criteria API相比,它读起来很流利,提高了可读性并提供了更多的灵活性。 这里唯一需要说明的是,提出规范实现需要相当多的编码工作。
以下是规范的一些优点:
- 所有“基本”查询都已实现,即findById,保存和删除
- 分页功能开箱即用。 您可以简单地将一个可分页对象从Controller传递到Service到您的存储库,并且可以正常工作(甚至可以排序)!
- 使用Spring的Specification API比普通的JPA简单一些,因为您只需创建谓词,而不必弄乱EntityManager和PersistenceContext。
如果您有任何要添加或共享的内容,请在下面的评论部分中留言。
祝大家学习愉快!
正确使用Spring Data JPA规范的更多相关文章
- Spring Data Jpa 规范接口表
Keyword Sample JPQL snippet And findByLastnameAndFirstname … where x.lastname = ?1 and x.firstname ...
- spring data jpa(一)
第1章 Spring Data JPA的快速入门 1.1 需求说明 Spring Data JPA完成客户的基本CRUD操作 1.2 搭建Spring Data JPA的开发环境 1. ...
- 12 Spring Data JPA:springDataJpa的运行原理以及基本操作(上)
spring data jpaday1:orm思想和hibernate以及jpa的概述和jpa的基本操作 day2:springdatajpa的运行原理 day2:springdatajpa的基本操作 ...
- 16 搭建Spring Data JPA的开发环境
使用Spring Data JPA,需要整合Spring与Spring Data JPA,并且需要提供JPA的服务提供者hibernate,所以需要导入spring相关坐标,hibernate坐标,数 ...
- Spring Data JPA 整合Spring
1.1 Spring Data JPA 与 JPA和hibernate之间的关系 JPA是一套规范,内部是有接口和抽象类组成的.hibernate是一套成熟的ORM框架,而且Hibernate实现 ...
- Spring Data JPA方法定义规范
Spring Data Jpa方法定义的规则: (1)简单条件查询 简单条件查询:查询某一个实体类或者集合. 按照Spring Data的规范的规定,查询方法以find | read | get开头, ...
- 74. Spring Data JPA方法定义规范【从零开始学Spring Boot】
[从零开始学习Spirng Boot-常见异常汇总] 事情的起因:有人问过我们这个这个问题:为什么我利用Spring data jpa写的方法没有按照我想要的情况进行执行呢?我记得当时只是告诉他你你先 ...
- 深入浅出学Spring Data JPA
第一章:Spring Data JPA入门 Spring Data是什么 Spring Data是一个用于简化数据库访问,并支持云服务的开源框架.其主要目标是使得对数据的访问变得方便快捷,并支持map ...
- 干货|一文读懂 Spring Data Jpa!
有很多读者留言希望松哥能好好聊聊 Spring Data Jpa!其实这个话题松哥以前零零散散的介绍过,在我的书里也有介绍过,但是在公众号中还没和大伙聊过,因此本文就和大家来仔细聊聊 Spring D ...
随机推荐
- C#&.Net干货分享-构造QRCoderHelper生成二维码图片
不想说废话,直接源码拿去用... /// <summary> /// 二维码管理 /// </summary> public class QRCoderHel ...
- RabbitMQ基础理解
RabbitMQ基本理解 MQ是消息中间件,常见的有RabbitMQ,Kafka,RocketMQ,activeMQ 等,用于分布式系统中.作用有三点 解耦 异步 削峰 RabbitMQ 整体上是一个 ...
- pycharm连接远程python的开发环境
一.准备工作 1.远程主机配置python的开发环境(pyenv) 2.本地windowsp安装pycharm 二.配置pycharm连接 配置运行环境:
- python 导入同级目录文件时报错
当你import的时候,python解释器只会在sys.path这个变量(一个list,你可以print出来看)里面的路径中找可能匹配的package或module. 而一个package跟一个普通文 ...
- if(response.isSuccess){}else{}的方式,如果我们由于忽略没有设置success字段的值,就可能导致
在日常开发中,我们会经常要在类中定义布尔类型的变量,比如在给外部系统提供一个RPC接口的时候,我们一般会定义一个字段表示本次请求是否成功的. 关于这个”本次请求是否成功”的字段的定义,其实是有很多种讲 ...
- Python文件操作:文件的打开关闭读取写入
Python文件操作:文件的打开关闭读取写入 一.文件的打开关闭 Python能以文本和二进制两种方式处理文件,本文主要讨论在Python3中文本文件的操作. 文件操作都分为以下几个步骤: 1.打开文 ...
- Linux查看文件或文件夹大小du命令
du命令用于显示目录或文件的大小. du会显示指定的目录或文件所占用的磁盘空间. 语法: du [-abcDhHklmsSx][-L <符号连接>][-X <文件>][--bl ...
- 手把手教你制作Jlink-OB调试器(含原理图、PCB、外壳、固件)
前言 好久没更新博客和公众号了,感谢大家还没取关哈,好吧,我承认是我太懒了,今天分享一个福利! 趁着前段时间嘉立创和捷配打价格战,一天之内,多次降价,看着真是热闹.捷配降到最低3元一款,而嘉立创降到最 ...
- go语言之map
go语言的map就相当于python的dict 1.map的初始化 //创建map //k的类型是int,v的类型是string var test25_1 map[int]string fmt.Pri ...
- NIO中Buffer的重要属性关系解析
Buffer 是java NIO中三个核心概念之一 缓存, 在java的实现体系中Buffer作为顶级抽象类存在 简单说,Buffer在做什么? 我们知道,在java IO中体系中, 因为InputS ...