定義 Repository 介面
要定義儲存庫介面,首先需要定義一個特定於領域類的儲存庫介面。該介面必須擴充套件 Repository,並指定領域類和 ID 型別。如果您想為該領域型別公開 CRUD 方法,您可以擴充套件 CrudRepository 或其變體之一,而不是 Repository。
微調儲存庫定義
有幾種方法可以開始使用您的儲存庫介面。
典型的方法是擴充套件 CrudRepository,它提供了 CRUD 功能的方法。CRUD 代表建立(Create)、讀取(Read)、更新(Update)、刪除(Delete)。在 3.0 版本中,我們還引入了 ListCrudRepository,它與 CrudRepository 非常相似,但對於返回多個實體的方法,它返回一個 List 而不是 Iterable,這可能更易於使用。
如果您正在使用響應式儲存,您可以選擇 ReactiveCrudRepository 或 RxJava3CrudRepository,具體取決於您使用的響應式框架。
如果您正在使用 Kotlin,您可以選擇利用 Kotlin 協程的 CoroutineCrudRepository。
此外,如果您需要允許指定 Sort 抽象(或在第一個情況下為 Pageable 抽象)的方法,您可以擴充套件 PagingAndSortingRepository、ReactiveSortingRepository、RxJava3SortingRepository 或 CoroutineSortingRepository。請注意,各種排序儲存庫不再像 Spring Data 3.0 之前的版本那樣擴充套件其各自的 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 Data 模組一起使用
在您的應用程式中使用唯一的 Spring Data 模組可以使事情變得簡單,因為定義範圍內的所有儲存庫介面都繫結到 Spring Data 模組。有時,應用程式需要使用多個 Spring Data 模組。在這種情況下,儲存庫定義必須區分持久化技術。當它在類路徑上檢測到多個儲存庫工廠時,Spring Data 會進入嚴格的儲存庫配置模式。嚴格配置使用儲存庫或領域類上的詳細資訊來決定儲存庫定義的 Spring Data 模組繫結
-
如果儲存庫定義擴充套件了特定模組的儲存庫,則它是特定 Spring Data 模組的有效候選者。
-
如果領域類使用特定模組的型別註解進行註解,則它是特定 Spring Data 模組的有效候選者。Spring Data 模組接受第三方註解(例如 JPA 的
@Entity)或提供自己的註解(例如 Spring Data MongoDB 和 Spring Data Elasticsearch 的@Document)。
以下示例展示了使用特定模組介面的儲存庫(在本例中為 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 { … }