定義儲存庫介面

要定義儲存庫介面,您首先需要定義一個特定於領域類別的儲存庫介面。該介面必須擴展 Repository 並指定領域類別和 ID 類型。 如果您想為該領域類型公開 CRUD 方法,您可以擴展 CrudRepository 或其變體之一,而不是 Repository

微調儲存庫定義

有幾種變體可以開始使用您的儲存庫介面。

典型的做法是擴展 CrudRepository,這為您提供 CRUD 功能的方法。CRUD 代表 Create、Read、Update、Delete。 在 3.0 版本中,我們還引入了 ListCrudRepository,它與 CrudRepository 非常相似,但對於那些返回多個實體的方法,它返回 List 而不是 Iterable,您可能會發現它更容易使用。

如果您使用的是反應式儲存區,您可以選擇 ReactiveCrudRepositoryRxJava3CrudRepository,具體取決於您使用的反應式框架。

如果您使用 Kotlin,您可以選擇 CoroutineCrudRepository,它利用了 Kotlin 的協程。

此外,如果您需要允許指定 Sort 抽象或在第一種情況下指定 Pageable 抽象的方法,您可以擴展 PagingAndSortingRepositoryReactiveSortingRepositoryRxJava3SortingRepositoryCoroutineSortingRepository。 請注意,各種排序儲存庫不再像 Spring Data 3.0 之前的版本那樣擴展各自的 CRUD 儲存庫。 因此,如果您想要兩者的功能,則需要同時擴展這兩個介面。

如果您不想擴展 Spring Data 介面,您也可以使用 @RepositoryDefinition 註解您的儲存庫介面。 擴展其中一個 CRUD 儲存庫介面會公開一整套方法來操作您的實體。 如果您希望有選擇性地公開要公開的方法,請將您想要公開的方法從 CRUD 儲存庫複製到您的領域儲存庫中。 這樣做時,您可以更改方法的回傳類型。 如果可能,Spring Data 將遵循回傳類型。 例如,對於傳回多個實體的方法,您可以選擇 Iterable<T>List<T>Collection<T> 或 VAVR 清單。

如果您的應用程式中的許多儲存庫都應該具有相同的方法集,您可以定義自己的基礎介面來繼承。 這樣的介面必須使用 @NoRepositoryBean 進行註解。 這可以防止 Spring Data 嘗試直接建立它的實例,並因為它無法確定該儲存庫的實體而失敗,因為它仍然包含泛型類型變數。

以下範例顯示如何有選擇性地公開 CRUD 方法(在本例中為 findByIdsave

選擇性地公開 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 尋找個別使用者,並觸發查詢以依電子郵件地址尋找 Users

中繼儲存庫介面使用 @NoRepositoryBean 進行註解。 請確保將該註解新增到 Spring Data 不應在執行階段建立實例的所有儲存庫介面。

將儲存庫與多個 Spring Data 模組一起使用

在您的應用程式中使用唯一的 Spring Data 模組使事情變得簡單,因為已定義範圍內的所有儲存庫介面都綁定到 Spring Data 模組。 有時,應用程式需要使用多個 Spring Data 模組。 在這種情況下,儲存庫定義必須區分持久性技術。 當它偵測到類別路徑上有多個儲存庫工廠時,Spring Data 會進入嚴格的儲存庫配置模式。 嚴格配置使用儲存庫或領域類別的詳細資訊來決定儲存庫定義的 Spring Data 模組綁定

  1. 如果儲存庫定義擴展了模組特定的儲存庫,則它是特定 Spring Data 模組的有效候選項。

  2. 如果領域類別使用模組特定的類型註解進行註解,則它是特定 Spring Data 模組的有效候選項。 Spring Data 模組接受協力廠商註解(例如 JPA 的 @Entity)或提供它們自己的註解(例如 Spring Data MongoDB 和 Spring Data Elasticsearch 的 @Document)。

以下範例顯示了使用模組特定介面(在本例中為 JPA)的儲存庫

範例 1. 使用模組特定介面的儲存庫定義
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 模組的有效候選項。

以下範例顯示了使用泛型介面的儲存庫

範例 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。

以下範例顯示了使用帶有註解的領域類別的儲存庫

範例 3. 使用帶有註解的領域類別的儲存庫定義
interface PersonRepository extends Repository<Person, Long> { … }

@Entity
class Person { … }

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

@Document
class User { … }

PersonRepository 引用了使用 JPA @Entity 註解進行註解的 Person,因此此儲存庫顯然屬於 Spring Data JPA。 UserRepository 引用了使用 Spring Data MongoDB 的 @Document 註解進行註解的 User

以下不良範例顯示了使用帶有混合註解的領域類別的儲存庫

範例 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 Data 模組的儲存庫候選項。 在同一個領域類型上使用多個持久性技術特定的註解是可能的,並且可以跨多個持久性技術重用領域類型。 但是,Spring Data 無法再確定要將儲存庫綁定到的唯一模組。

區分儲存庫的最後一種方法是透過劃定儲存庫基底套件的範圍。 基底套件定義了掃描儲存庫介面定義的起點,這意味著儲存庫定義位於適當的套件中。 預設情況下,註解驅動的配置使用配置類別的套件。 基於 XML 的配置中的基底套件是強制性的。

以下範例顯示了基底套件的註解驅動配置

基底套件的註解驅動配置
@EnableJpaRepositories(basePackages = "com.acme.repositories.jpa")
@EnableMongoRepositories(basePackages = "com.acme.repositories.mongo")
class Configuration { … }