此版本仍在开发中,尚不被认为是稳定的。对于最新的稳定版本,请使用 Spring Data Relational 3.5.2! |
定义存储库接口
要定义存储库接口,首先需要定义特定于域类的存储库接口。
接口必须扩展Repository
并键入域类和 ID 类型。
如果要公开该域类型的 CRUD 方法,可以扩展CrudRepository
,或其变体之一,而不是Repository
.
微调存储库定义
有几种变体可以开始使用存储库界面。
典型的方法是将CrudRepository
,它为您提供了 CRUD 功能的方法。
CRUD 代表创建、读取、更新、删除。
在 3.0 版本中,我们还引入了ListCrudRepository
这与CrudRepository
但是对于那些返回多个实体的方法,它返回一个List
而不是Iterable
您可能会发现它更容易使用。
如果您使用的是响应式存储,您可以选择ReactiveCrudRepository
或RxJava3CrudRepository
取决于您使用的响应式框架。
如果您使用的是 Kotlin,您可以选择CoroutineCrudRepository
它利用了 Kotlin 的协程。
此外,您可以扩展PagingAndSortingRepository
,ReactiveSortingRepository
,RxJava3SortingRepository
或CoroutineSortingRepository
如果您需要允许指定Sort
抽象或第一种情况下的Pageable
抽象化。
请注意,各种排序存储库不再像在 3.0 之前的 Spring Data 版本中那样扩展其各自的 CRUD 存储库。
因此,如果您想要两个接口的功能,则需要扩展这两个接口。
如果您不想扩展 Spring Data 接口,您还可以使用@RepositoryDefinition
.
扩展其中一个 CRUD 存储库接口会公开一套完整的方法来作实体。
如果您希望对要公开的方法有选择性,请将要公开的方法从 CRUD 存储库复制到域存储库中。
这样做时,您可以更改方法的返回类型。
如果可能,Spring Data 将遵循返回类型。
例如,对于返回多个实体的方法,您可以选择Iterable<T>
,List<T>
,Collection<T>
或 VAVR 列表。
如果应用程序中的许多存储库应该具有相同的方法集,则可以定义自己的基本接口以继承自中。
这样的接口必须用@NoRepositoryBean
.
这可以防止 Spring Data 尝试直接创建它的实例并失败,因为它无法确定该存储库的实体,因为它仍然包含泛型类型变量。
以下示例显示了如何有选择地公开 CRUD 方法 (findById
和save
,在本例中):
@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 查找单个用户,并触发查询以查找Users
通过电子邮件地址。
中间存储库接口用@NoRepositoryBean .
确保将该注释添加到 Spring Data 不应在运行时为其创建实例的所有存储库接口。 |
将存储库与多个 Spring 数据模块一起使用
在应用程序中使用唯一的 Spring Data 模块使事情变得简单,因为定义范围内的所有存储库接口都绑定到 Spring Data 模块。 有时,应用程序需要使用多个 Spring Data 模块。 在这种情况下,存储库定义必须区分持久性技术。 当它在类路径上检测到多个存储库工厂时,Spring Data 会进入严格的存储库配置模式。 严格配置使用存储库或域类的详细信息来决定存储库定义的 Spring Data 模块绑定:
-
如果存储库定义扩展了特定于模块的存储库,则它是特定 Spring Data 模块的有效候选者。
-
如果域类使用特定于模块的类型注释进行注释,则它是特定 Spring Data 模块的有效候选者。 Spring Data 模块接受任一第三方注释(例如 JPA 的
@Entity
)或提供自己的注释(例如@Document
适用于 Spring Data MongoDB 和 Spring Data Elasticsearch)。
以下示例显示了使用特定于模块的接口(在本例中为 JPA)的存储库:
interface MyRepository extends JpaRepository<User, Long> { }
@NoRepositoryBean
interface MyBaseRepository<T, ID> extends JpaRepository<T, ID> { … }
interface UserRepository extends MyBaseRepository<User, Long> { … }
MyRepository
和UserRepository
扩展JpaRepository
在它们的类型层次结构中。
它们是 Spring Data JPA 模块的有效候选者。
以下示例显示了使用通用接口的存储库:
interface AmbiguousRepository extends Repository<User, Long> { … }
@NoRepositoryBean
interface MyBaseRepository<T, ID> extends CrudRepository<T, ID> { … }
interface AmbiguousUserRepository extends MyBaseRepository<User, Long> { … }
AmbiguousRepository
和AmbiguousUserRepository
仅延伸Repository
和CrudRepository
在它们的类型层次结构中。
虽然这在使用唯一的 Spring Data 模块时很好,但多个模块无法区分这些存储库应该绑定到哪个特定的 Spring Data 。
以下示例显示了使用带有注释的域类的存储库:
interface PersonRepository extends Repository<Person, Long> { … }
@Entity
class Person { … }
interface UserRepository extends Repository<User, Long> { … }
@Document
class User { … }
PersonRepository
引用Person
,其中标注了 JPA@Entity
注释,因此该存储库显然属于 Spring Data JPA。UserRepository
引用User
,它用 Spring Data MongoDB 的@Document
注解。
以下错误示例显示了使用具有混合注释的域类的存储库:
interface JpaPersonRepository extends Repository<Person, Long> { … }
interface MongoDBPersonRepository extends Repository<Person, Long> { … }
@Entity
@Document
class Person { … }
此示例显示了同时使用 JPA 和 Spring Data MongoDB 注释的域类。
它定义了两个存储库,JpaPersonRepository
和MongoDBPersonRepository
.
一个用于 JPA,另一个用于 MongoDB。
Spring Data 不再能够区分存储库,这会导致未定义的行为。
存储库类型详细信息和区分域类注释用于严格的存储库配置,以识别特定 Spring Data 模块的存储库候选者。 可以在同一域类型上使用多个特定于持久性技术的注释,并允许跨多个持久性技术重用域类型。 但是,Spring Data 无法再确定要绑定存储库的唯一模块。
区分存储库的最后一种方法是确定存储库基础包的范围。 基本包定义了扫描存储库接口定义的起点,这意味着将存储库定义位于相应的包中。 默认情况下,注释驱动的配置使用配置类的包。 基于 XML 的配置中的基本包是强制性的。
以下示例显示了基本包的注释驱动配置:
@EnableJpaRepositories(basePackages = "com.acme.repositories.jpa")
@EnableMongoRepositories(basePackages = "com.acme.repositories.mongo")
class Configuration { … }