在优锐课的学习分享中探讨了关于,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. crontab -e 报错(E518: Unknown option: foldenable)

    crontab 默认编辑器为vi,不支持foldenable #crontab -e Error detected while processing /root/.vimrc: line : E518 ...

  2. 用iText5-2-其他类型PDF

    //设置文件属性的PDF package com.wf.zhang.test; import java.io.FileOutputStream; import com.itextpdf.text.Ba ...

  3. 解决CentOS7 Local time比实际时间相差8小时

    GPS系统中有两种时间区分,UTC就0时区的时间,CST为本地时间,如北京为早上八点(东八区),UTC时间比北京时晚八小时; CST:China Standard Time,UTC+8:00 中国沿海 ...

  4. PHP制作的掷色子点数抽奖游戏实例

    PHP制作的掷色子点数抽奖游戏实例,通过掷色子点数来达到抽奖的效果,为抽奖活动增添一些趣味性. 我们将在html页面中写下如下的html结构代码,.wrap用来放置色子和提示信息,#prize则是用来 ...

  5. thymeleaf Exception processing template "xxx": Exception parsing document: template="xxx", line 6 - column 3报错解决的几种方法

    我是在SpringBoot项目使用Thymeleaf作为模板引擎时报的错误 controller代码非常简单,如下所示: @RequestMapping("/abc") publi ...

  6. JS基础语法---总结

    JS是一门什么样的语言? 是一门解释性的语言 是一门脚本语言 是一门弱类型语言,声明变量都用var 是一门基于对象的语言 是一门动态类型的语言:            1. 代码(变量)只有执行到这个 ...

  7. UI视图控件、视图嵌套、SubView、Tag 的使用

    - (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchO ...

  8. Python遍历字典

    1.遍历key值 1 >>> d = {'Python':'astonishing', 'C++':'complicated', 'Java':'versatile'} 2 > ...

  9. Oracle 备份数据库

    [目录] ①备份数据库(https://www.cnblogs.com/xqz0618/p/oracle_backup.html) ②定时备份数据库(https://www.cnblogs.com/x ...

  10. 快速破解Goland

    两种激活方式永久激活:推荐优先使用,永久有效有效期激活:如果你实在激活不了又着急使用,这是备选激活方案,简单快捷 一.永久激活 1.下载新版破解补丁 点击链接 https://pan.baidu.co ...