此版本仍在开发中,尚未被视为稳定版本。如需最新稳定版本,请使用 Spring Data Cassandra 5.0.4spring-doc.cadn.net.cn

定义 Repository 接口

要定义一个仓库接口,首先需要定义一个特定于领域类的仓库接口。 该接口必须继承 Repository,并指定领域类和 ID 类型作为泛型参数。 如果你想为该领域类型暴露 CRUD 方法,可以改为继承 CrudRepository 或其某个变体,而不是直接继承 Repositoryspring-doc.cadn.net.cn

精细调整存储库定义

有几种方式可以开始使用您的仓库接口。spring-doc.cadn.net.cn

通常的做法是继承 CrudRepository,它为你提供了用于 CRUD 功能的方法。 CRUD 代表创建(Create)、读取(Read)、更新(Update)和删除(Delete)。 从 3.0 版本开始,我们还引入了 ListCrudRepository,它与 CrudRepository 非常相似,但针对那些返回多个实体的方法,它返回的是 List 而不是 Iterable,你可能会觉得这样更易于使用。spring-doc.cadn.net.cn

如果您使用的是响应式存储库,可以根据所使用的响应式框架选择 ReactiveCrudRepositoryRxJava3CrudRepositoryspring-doc.cadn.net.cn

如果你使用的是 Kotlin,可以选择利用 Kotlin 协程的 CoroutineCrudRepositoryspring-doc.cadn.net.cn

此外,如果你需要能够指定 PagingAndSortingRepository 抽象(或在第一种情况下指定 ReactiveSortingRepository 抽象)的方法,你可以扩展 RxJava3SortingRepositoryCoroutineSortingRepositorySortPageable。 请注意,从 Spring Data 3.0 版本开始,各种排序仓库接口不再像之前那样继承各自对应的 CRUD 仓库接口。 因此,如果你需要同时使用这两种功能,就必须同时继承这两个接口。spring-doc.cadn.net.cn

如果你不想继承 Spring Data 接口,也可以在你的仓库接口上使用 @RepositoryDefinition 注解。 继承某个 CRUD 仓库接口会暴露一整套用于操作实体的方法。 如果你希望有选择地暴露某些方法,可以从 CRUD 仓库中将你想要暴露的方法复制到你的领域仓库中。 这样做时,你可以更改这些方法的返回类型。 Spring Data 会在可能的情况下尊重你指定的返回类型。 例如,对于返回多个实体的方法,你可以选择 Iterable<T>List<T>Collection<T> 或 VAVR 列表。spring-doc.cadn.net.cn

如果你的应用程序中有多个仓库需要拥有相同的一组方法,你可以定义自己的基接口供它们继承。 此类接口必须使用 @NoRepositoryBean 注解。 这样可以防止 Spring Data 尝试直接创建该接口的实例而失败,因为此时仍包含泛型类型变量,Spring Data 无法确定该仓库对应的实体。spring-doc.cadn.net.cn

以下示例展示了如何有选择地暴露 CRUD 方法(在本例中为 findByIdsave):spring-doc.cadn.net.cn

选择性地暴露 CRUD 方法
@NoRepositoryBean
interface MyBaseRepository<T, ID> extends Repository<T, ID> {

  Optional<T> findById(ID id);

  <S extends T> S save(S entity);
}

interface UserRepository extends MyBaseRepository<User, Long> {
  User findByEmailAddress(EmailAddress emailAddress);
}

在前面的示例中,您为所有领域仓库定义了一个通用的基础接口,并暴露了 findById(…)save(…) 方法。这些方法会被路由到 Spring Data 所提供的、您所选存储技术对应的基础仓库实现中(例如,如果您使用 JPA,则实现类为 SimpleJpaRepository),因为它们与 CrudRepository 中的方法签名相匹配。 因此,UserRepository 现在可以保存用户、通过 ID 查找单个用户,并触发查询以通过电子邮件地址查找 Usersspring-doc.cadn.net.cn

中间的仓库接口使用 @NoRepositoryBean 注解进行标注。 请确保将该注解添加到所有 Spring Data 在运行时不应创建实例的仓库接口上。

使用多个 Spring Data 模块的存储库

在应用程序中使用唯一的 Spring Data 模块会使事情变得简单,因为定义范围内的所有仓库接口都会绑定到该 Spring Data 模块。 有时,应用程序需要使用多个 Spring Data 模块。 在这种情况下,仓库定义必须区分不同的持久化技术。 当 Spring Data 在类路径上检测到多个仓库工厂时,会进入严格的仓库配置模式。 严格配置会利用仓库或领域类的详细信息,来决定仓库定义应绑定到哪个 Spring Data 模块:spring-doc.cadn.net.cn

  1. 如果仓库定义扩展了特定模块的仓库,则它是该特定 Spring Data 模块的有效候选者。spring-doc.cadn.net.cn

  2. 如果领域类使用了特定于模块的类型注解进行标注,那么它就是对应 Spring Data 模块的有效候选。 Spring Data 模块既接受第三方注解(例如 JPA 的 @Entity),也提供自己的注解(例如用于 Spring Data MongoDB 和 Spring Data Elasticsearch 的 @Document)。spring-doc.cadn.net.cn

以下示例展示了一个使用模块特定接口(本例中为 JPA)的仓库:spring-doc.cadn.net.cn

示例 1. 使用模块特定接口的 Repository 定义
interface MyRepository extends JpaRepository<User, Long> { }

@NoRepositoryBean
interface MyBaseRepository<T, ID> extends JpaRepository<T, ID> { … }

interface UserRepository extends MyBaseRepository<User, Long> { … }

MyRepositoryUserRepository 在其类型层次结构中继承了 JpaRepository。 它们是 Spring Data JPA 模块的有效候选者。spring-doc.cadn.net.cn

以下示例展示了一个使用泛型接口的仓库:spring-doc.cadn.net.cn

示例2. 使用泛型接口的仓库定义
interface AmbiguousRepository extends Repository<User, Long> { … }

@NoRepositoryBean
interface MyBaseRepository<T, ID> extends CrudRepository<T, ID> { … }

interface AmbiguousUserRepository extends MyBaseRepository<User, Long> { … }

AmbiguousRepositoryAmbiguousUserRepository 在其类型层次结构中仅继承了 RepositoryCrudRepository。 虽然在使用唯一的 Spring Data 模块时这样做没有问题,但在存在多个模块的情况下,无法区分这些仓库应绑定到哪个特定的 Spring Data 模块。spring-doc.cadn.net.cn

以下示例展示了一个使用带注解的领域类的仓库:spring-doc.cadn.net.cn

示例 3. 使用带注解的领域类定义仓库
interface PersonRepository extends Repository<Person, Long> { … }

@Entity
class Person { … }

interface UserRepository extends Repository<User, Long> { … }

@Document
class User { … }

PersonRepository 引用了带有 JPA Person 注解的 @Entity,因此该仓库显然属于 Spring Data JPA。UserRepository 引用了带有 Spring Data MongoDB 的 User 注解的 @Documentspring-doc.cadn.net.cn

以下不良示例展示了一个使用带有混合注解的领域类的仓库:spring-doc.cadn.net.cn

示例 4. 使用带有混合注解的领域类定义仓库
interface JpaPersonRepository extends Repository<Person, Long> { … }

interface MongoDBPersonRepository extends Repository<Person, Long> { … }

@Entity
@Document
class Person { … }

此示例展示了一个同时使用 JPA 和 Spring Data MongoDB 注解的领域类。 它定义了两个仓库:JpaPersonRepositoryMongoDBPersonRepository。 其中一个用于 JPA,另一个用于 MongoDB。 Spring Data 无法再区分这两个仓库,从而导致未定义的行为。spring-doc.cadn.net.cn

仓库类型详情区分领域类注解 用于严格的仓库配置,以识别特定 Spring Data 模块的仓库候选者。 在同一领域类型上使用多种持久化技术特定的注解是可行的,并能实现领域类型在多种持久化技术之间的复用。 然而,Spring Data 将无法再确定一个唯一的模块来绑定该仓库。spring-doc.cadn.net.cn

区分仓库的最后一种方式是通过限定仓库基础包的范围。 基础包定义了扫描仓库接口定义的起始点,这意味着仓库定义必须位于相应的包中。 默认情况下,基于注解的配置会使用配置类所在的包。 在基于 XML 的配置中,基础包是必需的。spring-doc.cadn.net.cn

以下示例展示了基于注解驱动的基础包配置:spring-doc.cadn.net.cn

基于注解驱动的基础包配置
@EnableJpaRepositories(basePackages = "com.acme.repositories.jpa")
@EnableMongoRepositories(basePackages = "com.acme.repositories.mongo")
class Configuration { … }