Spring Data JPA中的CrudRepository和JpaRepository接口有什么区别?

1088
这篇文章讨论了Spring Data JPA中的CrudRepositoryJpaRepository接口之间的区别。尽管在网络上的示例中它们被交替使用,但它们之间确实存在差异。你为什么想要使用其中一个而不是另一个?请继续阅读以了解更多信息。

1
还要阅读本文的 Introduction to Spring Data Repositories 部分。 - Lucky
9个回答

1486

JpaRepository 扩展自 PagingAndSortingRepository,而 PagingAndSortingRepository 又扩展自 CrudRepository

它们的主要功能如下:

由于上述继承关系,JpaRepository 将具有 CrudRepositoryPagingAndSortingRepository 提供的所有功能。因此,如果您不需要存储库具有 JpaRepositoryPagingAndSortingRepository 提供的功能,请使用 CrudRepository


259
在findAll()中,返回一个List<>而不是Iterable<>。:-) - Hinotori

507

肯的答案基本正确,但我想在你问题中的“为什么要使用其中之一?”方面发表一下意见。

基础知识

您选择的存储库的基本接口具有两个主要目的。首先,允许Spring Data存储库基础设施找到您的接口并触发代理创建,以便将接口实例注入客户端。第二个目的是将所需功能尽可能多地引入接口,而无需声明额外的方法。

常见接口

Spring Data核心库附带了两个基础接口,公开了一组专用功能:

  • CrudRepository - CRUD方法
  • PagingAndSortingRepository - 分页和排序方法(扩展CrudRepository

存储特定接口

各个存储模块(例如JPA或MongoDB)公开了这些基础接口的存储特定扩展,以允许访问存储特定功能,如考虑某些存储细节的刷新或专用批处理。其中一个示例是JpaRepositorydeleteInBatch(…),它与delete(…)不同,因为它使用查询来删除给定的实体,这更有效率,但具有不触发JPA定义的级联(按规范定义)的副作用。

我们通常建议使用这些基础接口,因为它们将底层持久性技术暴露给客户端,从而加强了它们与存储库之间的耦合性。此外,您会远离存储库的原始定义,即“一组实体”,所以如果您可以,请使用PagingAndSortingRepository

自定义存储库基础接口

直接依赖于提供的基础接口的缺点是双重的。虽然这两个可能被视为理论,但我认为它们很重要,需要意识到:

  1. 依赖Spring Data存储库接口将您的存储库接口与库耦合在一起。我认为这不是特别问题,因为您在代码中可能会使用PagePageable等抽象。 Spring Data与commons-lang或Guava等其他通用库没有任何区别。只要它提供合理的好处,就没问题。
  2. 通过扩展例如CrudRepository,您一次性公开了完整的持久性方法集。这在大多数情况下也可能是好的,但您可能会遇到希望更细粒度地控制公开方法的情况,例如创建一个不包括CrudRepositorysave(…)delete(…)方法的ReadOnlyRepository

应对这两个缺点的解决方案是制作自己的基本存储库接口甚至一组这样的接口。在许多应用程序中,我看到了这样的东西:

interface ApplicationRepository<T> extends PagingAndSortingRepository<T, Long> { }

interface ReadOnlyRepository<T> extends Repository<T, Long> {

  // Al finder methods go here
}

第一个仓库接口是一些通用基础接口,实际上只修复了第一点,但也将ID类型绑定为Long以保持一致性。第二个接口通常从CrudRepositoryPagingAndSortingRepository中复制所有find…(…)方法,但不公开操纵这些方法。在参考文档中阅读更多有关该方法的信息。
简而言之,仓库抽象允许您完全根据架构和功能需求选择基础存储库。如果适合,使用提供的默认存储库,如果必要,请自定义存储库基础接口。除非不可避免,否则请远离特定于存储的存储库接口。

这应该是被接受的答案:它不仅更完整,而且更有权威性,因为它是由“Spring Data项目负责人”编写的。谢谢! - Pino
1
我很好奇为什么saveAndFlush只是JpaRepository之类的东西的一部分方法?刷新持久化上下文不是通用操作吗?如果不使用特定于技术的接口,我们该如何实现相同的功能 - 根据您的建议? - taylorcressy
@Oliver Drotbohm,非常抱歉这么晚才提问。你说“它们暴露了底层持久化技术”,但我认为JPA只是一个规范,而不是一个实现。例如,我使用Hibernate,但我尽量避免使用Hibernate特定的代码,我以为使用JPA类会更好,但可能有些地方我理解有误? - undefined

125

图片描述

摘要:

  • PagingAndSortingRepository 扩展自 CrudRepository

  • JpaRepository 扩展自 PagingAndSortingRepository

CrudRepository 接口提供了 CRUD(增删改查)操作的方法,因此它允许您在不定义自己的方法的情况下创建、读取、更新和删除记录。

PagingAndSortingRepository 提供了使用分页和排序检索实体的其他方法。

最后,JpaRepository 添加了一些特定于 JPA 的功能。


"extends Repository<>"是什么?它将有哪些方法?与CrudRepository相同吗? - s-kaczmarek

33

我正在学习Spring Data JPA。它可能会对你有所帮助: 输入图像描述


1
你好,很棒的方案。请问你使用哪个工具来生成这种方案? - Rozar Fabien
@RozarFabien 你几年前问过,希望你已经找到答案了,但我在这里放上来供别人参考。在这个问题的图片中,我不确定使用的是哪个工具,但你可以轻松地使用Intellij(或者他们的任何一款IDE,取决于你使用的语言)来完成。这是他们的文档链接:https://www.jetbrains.com/help/idea/class-diagram.html#analyze_class - Federico Baù
@RozarFabien,你几年前问过这个问题,希望你已经找到了答案,但我把它放在这里供其他人参考。在这个问题的图片中,我不确定使用的是哪个工具,但你可以很容易地使用Intellij(或者他们的任何IDE,根据你使用的语言而定)来做到这一点。这是他们的文档链接:https://www.jetbrains.com/help/idea/class-diagram.html#analyze_class - undefined

30
以下是CrudRepositoryJpaRepository之间的区别:

CrudRepository

  1. CrudRepository是一个基础接口,继承了Repository接口。
  2. CrudRepository主要提供CRUD(创建、读取、更新、删除)操作。
  3. saveAll()方法的返回类型为Iterable
  4. 使用场景 - 定义扩展CrudRepository的存储库以执行CRUD操作。

JpaRepository

  1. JpaRepository扩展了PagingAndSortingRepository,后者又扩展了CrudRepository
  2. JpaRepository提供了CRUD和分页操作,还提供了其他方法,如flush()saveAndFlush()deleteInBatch()等。
  3. saveAll()方法的返回类型为List
  4. 使用场景 - 定义扩展JpaRepository的存储库以执行CRUD和批量操作。

16

最新更新:spring-data-jpa 3.x

从现在开始使用spring-boot 3.xspring-core 6.xspring-data-jpa 3.x,结构和层次结构已经修改,看起来更清晰。

ListCrudRepository扩展了CrudRepository

ListPagingAndSortingRepository扩展PagingAndSortingRepository

JpaRepository同时扩展了ListCrudRepositoryListPagingAndSortingRepository

因此,基本上ListPagingAndSortingRepositoryListCrudRepository这两个新引入的接口现在代表旧接口的功能,但返回类型为List<T>,而剩余的PagingAndSortingRepositoryCrudRepository则处理Iterable<T>类型的返回值。

在新版本(3.x)中,结构如下:

enter image description here

在过去(3.0之前),许多声明返回List<T>的方法直接在JpaRepository中声明,但现在这些方法已被提取到ListPagingAndSortingRepositoryListCrudRepository中。

因此,在3.x版本之前的结构如下:

enter image description here

我希望从上面的图表中清楚地了解如何在3.x版本中修改所提到的JpaRepositoryCrudRepository

如果您计划将 spring-data-jpa2.x 版本迁移到 3.x 版本(如果您从 spring-boot 2.x 迁移到 spring-boot 3.x,则必须这样做),如上图所示,您应该预期在您的代码中使用了 PagingAndSortingRepository 的情况下会有破坏性代码,因为过去它是从 CrudRepository 继承的,因此直接扩展 PagingAndSortingRepository 的自定义存储库已经能够访问 CrudRepository 的方法。如果出现此问题,您应该通过调整自定义存储库以扩展 ListCrudRepositoryCrudRepository 来解决此问题。

9

所有答案都提供了足够的细节来回答问题。但是,让我添加更多的内容。

为什么要使用这些接口:

  • 它们允许 Spring 找到您的存储库接口并为其创建代理对象。
  • 它为您提供了一些常见操作的方法(您还可以自定义方法)。我喜欢这个功能,因为创建一个方法(并定义查询和准备语句,然后使用连接对象执行查询)来执行简单操作真的很麻烦!

每个接口的作用:

  • CrudRepository:提供CRUD函数
  • PagingAndSortingRepository:提供对记录进行分页和排序的方法
  • JpaRepository:提供JPA相关方法,例如刷新持久性上下文和批量删除记录

何时使用哪个接口:

根据 http://jtuts.com/2014/08/26/difference-between-crudrepository-and-jparepository-in-spring-data-jpa/

通常最好根据是否需要排序和分页来使用 CrudRepository PagingAndSortingRepository

如果可能的话,应该避免使用JpaRepository,因为它将您的存储库与JPA持久性技术绑定在一起,在大多数情况下,您可能甚至不会使用它提供的额外方法。


8

Spring Data JPA提供了JpaRepositoryCrudRepository接口,以简化JPA应用程序中数据访问库的创建。

CrudRepository是具有基本CRUD(创建、读取、更新、删除)操作的实体的基本接口。CrudRepository提供了一组最小的方法,如save()findAll()findById()delete()等,并可以通过其他自定义方法进行扩展。

这是代码示例:

public interface PersonEntityRepository extends CrudRepository<PersonEntity, Long> {

}

JpaRepository 接口扩展了 CrudRepository 接口。 JpaRepository 接口提供了其他基本 CRUD 操作之外的附加方法,例如:

  • findAll(Sort sort) - 返回按给定条件排序的所有实体的方法。
  • findAll(Pageable pageable) - 根据给定的分页和排序条件返回一个实体页面的方法。
  • flush() - 将所有待处理更改刷新到数据库的方法。
  • saveAndFlush(T entity) - 保存实体并立即将更改刷新到数据库的方法。 这是代码示例:
public interface PersonEntityRepository extends JpaRepository<PersonEntity, Long> {

    List<TestEntity> findByName(String name);

    List<Employee> findByAgeGreaterThan(double age);
}

你为什么要选择一个而不是另一个?
选择哪个取决于你的应用程序的具体需求。我建议使用 CrudRepository 接口进行基本的 CRUD 操作,使用 JpaRepository 接口进行更高级的功能,如分页、排序和立即将更改刷新到数据库。

2

Crud Repository是基础接口,充当标记接口。

JPA repository也扩展了PagingAndSorting repository。它提供了所有有用于实现分页的方法。Crud Repository不提供实现分页和排序的方法。

你可以参考-https://www.tutorialspoint.com/difference-between-crudrepository-and-jparepository-in-java#:~:text=Crud%20Repository%20is%20the%20base,acts%20as%20a%20marker%20interface.&text=JPA%20repository%20also%20extends%20the,for%20implementing%20pagination%20and%20sorting


3
CrudRepository 不是一个标记接口。在代码中也很少(可能为0)检查它的实例,因此它也不起到标记接口的作用。 - Jens Schauder

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接