原標(biāo)題:Spring認(rèn)證|使用 Spring Data Repositories(中)來源:(Spring中國教育管理中心) 4.4.5. 限制查詢結(jié)果 您可以使用first或top關(guān)鍵字來限制查詢方法的結(jié)果,,這兩個(gè)關(guān)鍵字可以互換使用,。您可以將一個(gè)可選的數(shù)值附加到top或first指定要返回的最大結(jié)果大小。如果忽略該數(shù)字,,則假定結(jié)果大小為 1,。以下示例顯示了如何限制查詢大小: 示例 20. 使用Top和限制查詢的結(jié)果大小First User findFirstByOrderByLastnameAsc(); User findTopByOrderByAgeDesc(); Page queryFirst10ByLastname(String lastname, Pageable pageable); Slice findTop3ByLastname(String lastname, Pageable pageable); List findFirst10ByLastname(String lastname, Sort sort); List findTop10ByLastname(String lastname, Pageable pageable); 限制表達(dá)式還支持Distinct支持不同查詢的數(shù)據(jù)存儲(chǔ)的關(guān)鍵字,。此外,,對(duì)于將結(jié)果集限制為一個(gè)實(shí)例的查詢,Optional支持將結(jié)果用關(guān)鍵字包裝,。 如果分頁或切片應(yīng)用于限制查詢分頁(以及可用頁數(shù)的計(jì)算),,則在受限結(jié)果內(nèi)應(yīng)用。 通過使用Sort參數(shù)限制結(jié)果與動(dòng)態(tài)排序相結(jié)合,,您可以表達(dá)“K”最小元素和“K”最大元素的查詢方法,。 4.4.6. 返回集合或可迭代對(duì)象的存儲(chǔ)庫方法 查詢方法,返回多個(gè)結(jié)果可以使用標(biāo)準(zhǔn)的Java Iterable,,List和Set,。除此之外,我們支持返回 Spring Data 的Streamable,、 的自定義擴(kuò)展Iterable以及Vavr提供的集合類型,。請(qǐng)參閱解釋所有可能的查詢方法返回類型的附錄。 使用 Streamable 作為查詢方法返回類型 您可以使用任何集合類型的Streamable替代Iterable品,。它提供了訪問非并行Stream(缺少 from Iterable)的便捷方法,,以及直接….filter(…)和….map(…)覆蓋元素并將其連接Streamable到其他元素的能力: 示例 21. 使用 Streamable 組合查詢方法結(jié)果 interface PersonRepository extends Repository { Streamable findByFirstnameContaining(String firstname); Streamable findByLastnameContaining(String lastname); } Streamable result = repository.findByFirstnameContaining("av") .and(repository.findByLastnameContaining("ea")); 返回自定義流包裝器類型 為集合提供專用包裝器類型是一種常用模式,用于為返回多個(gè)元素的查詢結(jié)果提供 API,。通常,,通過調(diào)用存儲(chǔ)庫方法返回類集合類型并手動(dòng)創(chuàng)建包裝器類型的實(shí)例來使用這些類型。您可以避免該額外步驟,,因?yàn)?Spring Data 允許您將這些包裝器類型用作查詢方法返回類型,,前提是它們滿足以下條件: 類型實(shí)現(xiàn)Streamable. 的類型公開任一個(gè)構(gòu)造或命名靜態(tài)工廠法of(…)或valueOf(…)該取Streamable作為參數(shù)。 以下清單顯示了一個(gè)示例: class Product { MonetaryAmount getPrice() { … } } @RequiredArgsConstructor(staticName = "of") class Products implements Streamable { private final Streamable streamable; public MonetaryAmount getTotal() { return streamable.stream() .map(Priced::getPrice) .reduce(Money.of(0), MonetaryAmount::add); } @Override public Iterator iterator() { return streamable.iterator(); } } interface ProductRepository implements Repository { Products findAllByDescriptionContaining(String text); } 一個(gè)Product暴露的API來訪問產(chǎn)品的價(jià)格實(shí)體。 Streamable可以通過使用Products.of(…)(使用 Lombok 注釋創(chuàng)建的工廠方法)構(gòu)造的的包裝器類型,。采用Streamablewill 的標(biāo)準(zhǔn)構(gòu)造函數(shù)也可以,。 包裝器類型公開了一個(gè)額外的 API,在Streamable. 實(shí)現(xiàn)Streamable接口并委托給實(shí)際結(jié)果,。 該包裝器類型Products可以直接用作查詢方法返回類型,。您不需要Streamable在存儲(chǔ)庫客戶端中的查詢之后返回并手動(dòng)包裝它。 支持 Vavr 集合 Vavr是一個(gè)包含 Java 函數(shù)式編程概念的庫,。它附帶一組自定義集合類型,,您可以將其用作查詢方法返回類型,如下表所示: 您可以使用第一列(或其子類型)中的類型作為查詢方法返回類型,,并根據(jù)實(shí)際查詢結(jié)果(第三列)的 Java 類型獲取第二列中的類型作為實(shí)現(xiàn)類型,。或者,,您可以聲明Traversable(Iterable相當(dāng)于Vavr ),然后我們從實(shí)際返回值派生實(shí)現(xiàn)類,。也就是說,, ajava.util.List變成了 VavrList或Seq, ajava.util.Set變成了 Vavr LinkedHashSet Set,,依此類推,。 4.4.7. 存儲(chǔ)庫方法的空處理 從 Spring Data 2.0 開始,返回單個(gè)聚合實(shí)例的存儲(chǔ)庫 CRUD 方法使用 Java 8Optional來指示可能缺少值,。除此之外,,Spring Data 支持在查詢方法上返回以下包裝器類型: com.google.common.base.Optional scala.Option io.vavr.control.Option 或者,查詢方法可以選擇根本不使用包裝器類型,。然后通過返回來指示不存在查詢結(jié)果null,。返回集合、集合替代,、包裝器和流的存儲(chǔ)庫方法保證永遠(yuǎn)不會(huì)返回null,,而是返回相應(yīng)的空表示。有關(guān)詳細(xì)信息,,請(qǐng)參閱“存儲(chǔ)庫查詢返回類型”,。 可空性注釋 您可以使用Spring Framework 的可空性注釋來表達(dá)存儲(chǔ)庫方法的可空性約束。它們null在運(yùn)行時(shí)提供了一種工具友好的方法和選擇加入檢查,,如下所示: @NonNullApi: 在包級(jí)別上用于聲明參數(shù)和返回值的默認(rèn)行為分別是既不接受也不產(chǎn)生null值,。 @NonNull: 用于不得為的參數(shù)或返回值null(在@NonNullApi適用的參數(shù)和返回值上不需要)。 @Nullable: 用于可以是的參數(shù)或返回值null,。 Spring 注釋使用JSR 305注釋(一種休眠但廣泛使用的 JSR)進(jìn)行元注釋,。JSR 305 元注釋讓工具供應(yīng)商(例如IDEA、Eclipse和Kotlin)以通用方式提供空安全支持,而無需對(duì) Spring 注釋進(jìn)行硬編碼支持,。要為查詢方法啟用可空性約束的運(yùn)行時(shí)檢查,,您需要使用 Spring 的@NonNullApiin在包級(jí)別激活非可空性package-info.java,如以下示例所示: 示例 22. 在 package-info.java @org.springframework.lang.NonNullApi package com.acme; 一旦非空默認(rèn)設(shè)置到位,,存儲(chǔ)庫查詢方法調(diào)用將在運(yùn)行時(shí)驗(yàn)證為可空性約束,。如果查詢結(jié)果違反了定義的約束,則拋出異常,。當(dāng)該方法將返回null但被聲明為不可為空時(shí)(在存儲(chǔ)庫所在的包上定義的默認(rèn)注釋),,就會(huì)發(fā)生這種情況。如果您想再次選擇可空結(jié)果,,請(qǐng)有選擇地使用@Nullable單個(gè)方法,。使用本節(jié)開頭提到的結(jié)果包裝器類型繼續(xù)按預(yù)期工作:空結(jié)果被轉(zhuǎn)換為表示不存在的值。 以下示例顯示了剛剛描述的許多技術(shù): 示例 23.使用不同的可空性約束 package com.acme; import org.springframework.lang.Nullable; interface UserRepository extends Repository { User getByEmailAddress(EmailAddress emailAddress); @Nullable User findByEmailAddress(@Nullable EmailAddress emailAdress); Optional findOptionalByEmailAddress(EmailAddress emailAddress); } 存儲(chǔ)庫駐留在我們定義了非空行為的包(或子包)中,。 EmptyResultDataAccessException當(dāng)查詢未產(chǎn)生結(jié)果時(shí)拋出,。IllegalArgumentException當(dāng)emailAddress傳遞給方法是時(shí)拋出null。 null當(dāng)查詢未產(chǎn)生結(jié)果時(shí)返回,。也接受null作為 的值emailAddress,。 Optional.empty()當(dāng)查詢未產(chǎn)生結(jié)果時(shí)返回。IllegalArgumentException當(dāng)emailAddress傳遞給方法是時(shí)拋出null,。 基于 Kotlin 的存儲(chǔ)庫中的可空性 Kotlin在語言中定義了可空性約束,。Kotlin 代碼編譯為字節(jié)碼,它不通過方法簽名而是通過編譯元數(shù)據(jù)來表達(dá)可空性約束,。確保kotlin-reflect在您的項(xiàng)目中包含JAR 以啟用對(duì) Kotlin 的可空性約束的內(nèi)省,。Spring Data 存儲(chǔ)庫使用語言機(jī)制來定義這些約束以應(yīng)用相同的運(yùn)行時(shí)檢查,如下所示: 示例 24.在 Kotlin 存儲(chǔ)庫上使用可空性約束 interface UserRepository : Repository { fun findByUsername(username: String): User fun findByFirstname(firstname: String?): User? } 該方法將參數(shù)和結(jié)果都定義為不可為空(Kotlin 默認(rèn)值),。Kotlin 編譯器拒絕傳遞null給方法的方法調(diào)用,。如果查詢產(chǎn)生空結(jié)果,EmptyResultDataAccessException則拋出an ,。 該方法接受null的firstname參數(shù),,并返回null,如果查詢不產(chǎn)生結(jié)果,。 4.4.8. 流式查詢結(jié)果 您可以使用 Java 8Stream作為返回類型以增量方式處理查詢方法的結(jié)果,。不是將查詢結(jié)果包裝在 a 中Stream,而是使用數(shù)據(jù)存儲(chǔ)特定的方法來執(zhí)行流式傳輸,,如以下示例所示: 示例 25. 使用 Java 8 流式傳輸查詢結(jié)果 Stream @Query("select u from User u") Stream findAllByCustomQueryAndStream(); Stream readAllByFirstnameNotNull(); @Query("select u from User u") Stream streamAllPaged(Pageable pageable); AStream潛在地包裝了底層數(shù)據(jù)存儲(chǔ)特定的資源,,因此必須在使用后關(guān)閉。您可以Stream使用close()方法或使用 Java 7try-with-resources塊手動(dòng)關(guān)閉,,如以下示例所示: 示例 26.Stream在try-with-resources塊中處理結(jié)果 try (Stream stream = repository.findAllByCustomQueryAndStream()) { stream.forEach(…); } 并非所有 Spring Data 模塊當(dāng)前都支持Stream作為返回類型,。 4.4.9. 異步查詢結(jié)果 您可以使用Spring 的異步方法運(yùn)行能力異步運(yùn)行存儲(chǔ)庫查詢,。這意味著該方法在調(diào)用時(shí)立即返回,而實(shí)際查詢發(fā)生在已提交給 Spring 的任務(wù)中TaskExecutor,。異步查詢不同于反應(yīng)式查詢,,不應(yīng)混合使用。有關(guān)反應(yīng)式支持的更多詳細(xì)信息,,請(qǐng)參閱商店特定的文檔,。以下示例顯示了一些異步查詢: @Async Future findByFirstname(String firstname); @Async CompletableFuture findOneByFirstname(String firstname); @Async ListenableFuture findOneByLastname(String lastname); 使用java.util.concurrent.Future作為返回類型。 使用 Java 8java.util.concurrent.CompletableFuture作為返回類型,。 使用 aorg.springframework.util.concurrent.ListenableFuture作為返回類型,。 4.5. 創(chuàng)建存儲(chǔ)庫實(shí)例 本節(jié)介紹如何為定義的存儲(chǔ)庫接口創(chuàng)建實(shí)例和 bean 定義。一種方法是使用支持存儲(chǔ)庫機(jī)制的每個(gè) Spring Data 模塊附帶的 Spring 命名空間,,盡管我們通常建議使用 Java 配置,。 4.5.1. XML 配置 每個(gè) Spring Data 模塊都包含一個(gè)repositories元素,可讓您定義 Spring 為您掃描的基本包,,如以下示例所示: 示例 27. 通過 XML 啟用 Spring Data 存儲(chǔ)庫 xmlns:xsi="http://www./2001/XMLSchema-instance" xmlns="http://www./schema/data/jpa" xsi:schemaLocation="http://www./schema/beans https://www./schema/beans/spring-beans.xsd http://www./schema/data/jpa https://www./schema/data/jpa/spring-jpa.xsd"> 在前面的示例中,,指示 Spring 掃描com.acme.repositories及其所有子包以查找擴(kuò)展Repository的接口或其子接口之一。對(duì)于找到的每個(gè)接口,,基礎(chǔ)結(jié)構(gòu)注冊(cè)特定FactoryBean于持久性技術(shù)以創(chuàng)建處理查詢方法調(diào)用的適當(dāng)代理,。每個(gè) bean 都在從接口名稱派生的 bean 名稱下注冊(cè),因此 的接口UserRepository將在 下注冊(cè)u(píng)serRepository,。嵌套存儲(chǔ)庫接口的 Bean 名稱以其封閉的類型名稱為前綴。該base-package屬性允許使用通配符,,以便您可以定義掃描包的模式,。 使用過濾器 默認(rèn)情況下,基礎(chǔ)設(shè)施會(huì)選擇每個(gè)接口,,這些接口擴(kuò)展Repository位于配置的基本包下的持久性技術(shù)特定的子接口,,并為其創(chuàng)建一個(gè) bean 實(shí)例。但是,,您可能希望更精細(xì)地控制哪些接口為其創(chuàng)建了 bean 實(shí)例,。為此,請(qǐng)?jiān)谠貎?nèi)使用和元素,。語義完全等同于 Spring 上下文命名空間中的元素,。有關(guān)詳細(xì)信息,請(qǐng)參閱這些元素的Spring 參考文檔,。 例如,,要將某些接口從實(shí)例化中排除為存儲(chǔ)庫 bean,您可以使用以下配置: 示例 28. 使用 exclude-filter 元素 前面的示例排除了所有以SomeRepository實(shí)例化結(jié)尾的接口,。 內(nèi)容來源:(Spring中國教育管理中心) 使用 Spring Data Repositories,,未完待續(xù)..... |
|