在优锐课的学习分享中探讨了关于,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相比,它读起来很流利,提高了可读性并提供了更多的灵活性。 这里唯一需要说明的是,提出规范实现需要相当多的编码工作。

以下是规范的一些优点:

  1. 所有“基本”查询都已实现,即findById,保存和删除
  2. 分页功能开箱即用。 您可以简单地将一个可分页对象从Controller传递到Service到您的存储库,并且可以正常工作(甚至可以排序)!
  3. 使用Spring的Specification API比普通的JPA简单一些,因为您只需创建谓词,而不必弄乱EntityManager和PersistenceContext。

如果您有任何要添加或共享的内容,请在下面的评论部分中留言。

祝大家学习愉快!

正确使用Spring Data JPA规范的更多相关文章

  1. Spring Data Jpa 规范接口表

      Keyword Sample JPQL snippet And findByLastnameAndFirstname … where x.lastname = ?1 and x.firstname ...

  2. spring data jpa(一)

    第1章     Spring Data JPA的快速入门 1.1   需求说明 Spring Data JPA完成客户的基本CRUD操作 1.2   搭建Spring Data JPA的开发环境 1. ...

  3. 12 Spring Data JPA:springDataJpa的运行原理以及基本操作(上)

    spring data jpaday1:orm思想和hibernate以及jpa的概述和jpa的基本操作 day2:springdatajpa的运行原理 day2:springdatajpa的基本操作 ...

  4. 16 搭建Spring Data JPA的开发环境

    使用Spring Data JPA,需要整合Spring与Spring Data JPA,并且需要提供JPA的服务提供者hibernate,所以需要导入spring相关坐标,hibernate坐标,数 ...

  5. Spring Data JPA 整合Spring

    1.1   Spring Data JPA 与 JPA和hibernate之间的关系 JPA是一套规范,内部是有接口和抽象类组成的.hibernate是一套成熟的ORM框架,而且Hibernate实现 ...

  6. Spring Data JPA方法定义规范

    Spring Data Jpa方法定义的规则: (1)简单条件查询 简单条件查询:查询某一个实体类或者集合. 按照Spring Data的规范的规定,查询方法以find | read | get开头, ...

  7. 74. Spring Data JPA方法定义规范【从零开始学Spring Boot】

    [从零开始学习Spirng Boot-常见异常汇总] 事情的起因:有人问过我们这个这个问题:为什么我利用Spring data jpa写的方法没有按照我想要的情况进行执行呢?我记得当时只是告诉他你你先 ...

  8. 深入浅出学Spring Data JPA

    第一章:Spring Data JPA入门 Spring Data是什么 Spring Data是一个用于简化数据库访问,并支持云服务的开源框架.其主要目标是使得对数据的访问变得方便快捷,并支持map ...

  9. 干货|一文读懂 Spring Data Jpa!

    有很多读者留言希望松哥能好好聊聊 Spring Data Jpa!其实这个话题松哥以前零零散散的介绍过,在我的书里也有介绍过,但是在公众号中还没和大伙聊过,因此本文就和大家来仔细聊聊 Spring D ...

随机推荐

  1. 如何实现用户的历史记录功能(最多n条)

    使用容量为n的队列存储历史记录 使用标准库collections中的deque,它是一个双端循环队列 from collections import deque q = deque([], 5) #参 ...

  2. Mysql模式匹配两种方法

    一.使用LIKE或NOT LIKE比较操作符 使用 "_" 匹配任何单个字符,而 "%" 匹配任意数量的字符(包括零字符): 例如: 1.要想找出以“b”开头的 ...

  3. 设计模式-工厂模式(Factory)(创建型模式)

    以下代码来源: 设计模式精解-GoF 23种设计模式解析附C++实现源码 //Product.h #pragma once class Product { public: ; protected: P ...

  4. 百度云盘资源 for MAC 第三方工具不限速下载

    相信大家都比较困惑,百度网盘客户端限速后一般只有几十K的下载速度,Windows有百度网盘破解版,但MAC的破解版似乎不存在,要提速的话,一般的做法是开超级会员(27元/月),身为程序员的我们,是不是 ...

  5. 使用python解析ip地址

    前言 想要批量将ip地址转换为省份城市.国家或是经纬度?百度上的批量查找每次的容量太小满足不了要求?第三方库神器 - geoip2帮你解决所有烦恼. 准备工作 首先安装一下geoip2库, pip i ...

  6. IT兄弟连 HTML5教程 HTML5文字版面和编辑标签 HTML框架结构

    使用HTML框架结构可以把一个浏览器窗口划分为若干个小窗口,每个窗口可以显示不同的URL网页,每个框架里的网页相互独立.这样不仅可以非常方便地在浏览器中同时浏览不同的页面效果,而且可以非常方便地完成导 ...

  7. java8-计算时间差的方法

    一.简述 在Java8中,我们可以使用以下类来计算日期时间差异: 1.Period 2.Duration 3.ChronoUnit 二.Period类 主要是Period类方法getYears(),g ...

  8. javaWeb核心技术第五篇之jQuery

    - 概述 - jQuery是一个优秀的javascript框架(js类库),兼容css3和各大浏览器,提供dom,events,animate,ajax等简易的操作.并且jQuery有非常丰富的插件, ...

  9. NIO基础方法一

    1.remaining();返回当前位置与limit之间得元素数. int[] intArray={1,2,3,4}; IntBuffer intBuffer=IntBuffer.wrap(intAr ...

  10. 2019 DevOps 必备面试题——DevOps 理念篇

    原文地址:https://medium.com/edureka/devops-interview-questions-e91a4e6ecbf3 原文作者:Saurabh Kulshrestha 翻译君 ...