欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解Spring Data JPA中Repository的接口查詢方法

 更新時間:2022年04月28日 10:47:49   作者:嫣夜來  
repository代理有兩種方式從方法名中派生出特定存儲查詢:通過直接從方法名派生查詢和通過使用一個手動定義的查詢。本文將通過示例詳細講解Spring Data JPA中Repository的接口查詢方法,需要的可以參考一下

1.查詢方法定義詳解

repository代理有兩種方式從方法名中派生出特定存儲查詢。

  • 通過直接從方法名派生查詢。
  • 通過使用一個手動定義的查詢。

可用的選項取決于實際的商店。然而,必須有一個策略來決定創(chuàng)建什么實際的查詢。

2.搜索查詢策略

下列策略可用于repository解決基礎設施查詢。對于 XML 配置,你可以通過 query-lookup-strategy 屬性在命名空間配置該策略。對于 Java 配置,你可以使用 Enable${store}Repositories 注解的 queryLookupStrategy屬性。某些策略可能不被特定的數(shù)據(jù)存儲所支持。

  • CREATE; 試圖從查詢方法的名稱中構建一個特定于存儲的查詢。一般的做法是,從方法名中刪除一組已知的前綴,然后解析方法的其余部分。
  • USE_DECLARED_QUERY; 試圖找到一個已聲明的查詢,如果找不到則拋出一個異常。查詢可以由某個注解來定義,也可以通過其他方式來聲明。請參閱特定存儲的文檔以找到該存儲的可用選項。如果版本庫基礎設施在啟動時沒有為該方法找到一個已聲明的查詢,則會失敗。
  • CREATE_IF_NOT_FOUND;(默認)結合了 CREATE 和 USE_DECLARED_QUERY。它首先查找一個已聲明的查詢,如果沒有找到已聲明的查詢,它將創(chuàng)建一個基于方法名的自定義查詢。這是默認的查詢策略,因此,如果你沒有明確地配置任何東西,就會使用這種策略。它允許通過方法名快速定義查詢,但也可以根據(jù)需要通過引入已聲明的查詢對這些查詢進行自定義調(diào)整。

3.查詢創(chuàng)建

內(nèi)置在Spring Data repository基礎框架中,查詢生成器機制對于在repository的實體上建立約束性查詢非常有用。

例1. 從方法名創(chuàng)建查詢

interface PersonRepository extends Repository<Person, Long> {
  List<Person> findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname);

  // 查詢中添加去重關鍵字
  List<Person> findDistinctPeopleByLastnameOrFirstname(String lastname, String firstname);
  List<Person> findPeopleDistinctByLastnameOrFirstname(String lastname, String firstname);

  // 查詢中關鍵字忽略大小寫
  List<Person> findByLastnameIgnoreCase(String lastname);
  
  // Enabling ignoring case for all suitable properties
  List<Person> findByLastnameAndFirstnameAllIgnoreCase(String lastname, String firstname);

  // 查詢使用使用靜態(tài)排序規(guī)則
  List<Person> findByLastnameOrderByFirstnameAsc(String lastname);
  List<Person> findByLastnameOrderByFirstnameDesc(String lastname);
}

解析查詢方法名稱分為 主語和 謂語。

第一部分(find…By, exists…By)定義了查詢的主語,

第二部分構成了謂語。引入句(主語)可以包含進一步的表達。

在find(或其他引入關鍵詞)和By之間的任何文本都被認為是描述性的,除非使用一個限制結果的關鍵詞,如Distinct在要創(chuàng)建的查詢上設置一個不同的標志,或Top/First來限制查詢結果。

附錄中包含了查詢方法主語關鍵詞和查詢方法謂語關鍵詞的完整列表,包括排序和字母修飾語。然而,第一個By作為分界符,表示實際條件謂詞的開始。在一個非常基本的層面上,你可以在實體屬性上定義條件,并用And和Or來連接它們。

解析方法的實際結果取決于你為之創(chuàng)建查詢的持久性存儲。然而,有一些一般性約束需要注意:

  • 表達式通常是屬性遍歷與可以串聯(lián)的運算符的結合。你可以用AND和OR來組合屬性表達式。你還可以得到對運算符的支持,如屬性表達式的Between、LessThan、GreaterThan和Like。支持的運算符可能因數(shù)據(jù)存儲的不同而不同,所以請查閱參考文檔的適當部分。
  • 方法解析器支持為單個屬性(例如,findByLastnameIgnoreCase(…))或支持忽略大小寫的類型的所有屬性(通常是字符串實例–例如,findByLastnameAndFirstnameAllIgnoreCase(…))設置忽略大小寫標志。是否支持忽略大小寫可能因商店而異,所以請查閱參考文檔中的相關章節(jié),了解特定商店的查詢方法。
  • 你可以通過在引用屬性的查詢方法中附加一個OrderBy子句,并提供一個排序方向(Asc或Desc)來應用靜態(tài)排序。要創(chuàng)建一個支持動態(tài)排序的查詢方法,請參閱 “特殊參數(shù)處理”。

4.屬性表達式

屬性表達式只能引用被管理實體的一個直接屬性,如前面的例子所示。在查詢創(chuàng)建時,你已經(jīng)確保解析的屬性是被管理的實體類的一個對應屬性。然而,你也可以通過遍歷嵌套屬性來定義約束。考慮一下下面的方法簽名。

例2

List<Person> findByAddressZipCode(ZipCode zipCode);

假設一個人有一個帶有ZipCode的地址。在這種情況下,該方法創(chuàng)建x.address.zipCode屬性遍歷。解析算法首先將整個部分(AddressZipCode)解釋為屬性,并檢查實體類中是否有該名稱的屬性(未加首字母)。如果算法成功,它就使用該屬性。如果沒有,該算法將原始的駱駝字母部分從右側分割成頭和尾,并試圖找到相應的屬性–在我們的例子中,是AddressZip和Code。如果該算法找到了具有該頭部的屬性,它就取其尾部,并從那里繼續(xù)向下構建樹,以剛才描述的方式將尾部分割開來。如果第一次分割不匹配,該算法將分割點移到左邊(Address, ZipCode),然后繼續(xù)。

雖然這在大多數(shù)情況下應該是有效的,但該算法有可能選擇錯誤的屬性。假設人的類也有一個addressZip屬性。該算法將在第一輪分割中已經(jīng)匹配,選擇錯誤的屬性,并且失?。ㄒ驗閍ddressZip的類型可能沒有代碼屬性)。

為了解決這種模糊性,你可以在你的方法名里面使用_來手動定義遍歷點。所以我們的方法名將如下。

例3

List<Person> findByAddress_ZipCode(ZipCode zipCode);

因為我們把下劃線字符當作一個保留字符,所以我們強烈建議遵循標準的Java命名慣例(也就是說,不要在屬性名中使用下劃線,而是使用駱駝大寫)。

5.特殊參數(shù)處理

為了處理你的查詢中的參數(shù),定義方法參數(shù),正如在前面的例子中已經(jīng)看到的。除此之外,基礎設施還能識別某些特定的類型,如 Pageable和 Sort,以動態(tài)地將 分頁和 排序應用于你的查詢。下面的例子演示了這些功能。

例4 在查詢方法中使用分頁、切割、排序

Page<User> findByLastname(String lastname, Pageable pageable);
Slice<User> findByLastname(String lastname, Pageable pageable);
List<User> findByLastname(String lastname, Sort sort);
List<User> findByLastname(String lastname, Pageable pageable);

注意:采取Sort和Pageable的API希望將非空值交到方法中。如果你不想應用任何排序或分頁,請使用Sort.unsorted()和Pageable.unpaged()方法。

第一個方法讓你把org.springframework.data.domain.Pageable實例傳遞給query方法,以動態(tài)地將分頁添加到你靜態(tài)定義的查詢中。一個Page知道可用的元素和頁面的總數(shù)。它是通過基礎設施觸發(fā)一個計數(shù)查詢來計算總數(shù)量。

由于這可能是昂貴的(取決于使用的存儲),你可以改成返回一個Slice。一個Slice只知道下一個Slice是否可用,這在走過一個較大的結果集時可能就足夠了。

排序選項也是通過Pageable實例處理的。如果你只需要排序,可以在你的方法中添加一個org.springframework.data.domain.Sort參數(shù)。正如你所看到的,返回一個List也是可能的。在這種情況下,構建實際的Page實例所需的額外元數(shù)據(jù)并沒有被創(chuàng)建(這反過來意味著不需要發(fā)出額外的計數(shù)查詢)。相反,它限制了查詢,只查詢給定范圍的實體。

要想知道你在整個查詢中得到多少頁,你必須觸發(fā)一個額外的計數(shù)查詢。默認情況下,這個查詢是由你實際觸發(fā)的查詢派生出來的。

分頁和排序

我們可以通過使用屬性名稱來定義簡單的排序表達式。你可以將表達式連接起來,將多個標準收集到一個表達式中。

例5 定義排序表達式

Sort sort = Sort.by("firstname").ascending()
  .and(Sort.by("lastname").descending());

對于定義排序表達式的更加類型安全的方式,從定義排序表達式的類型開始,使用方法引用來定義排序的屬性。

例6 通過使用類型安全的API來定義排序表達式

TypedSort<Person> person = Sort.sort(Person.class);

Sort sort = person.by(Person::getFirstname).ascending()
  .and(person.by(Person::getLastname).descending());

TypedSort.by(…)通過(通常)使用CGlib來使用運行時代理,這在使用Graal VM Native等工具時可能會干擾本地圖像的編譯。

如果你的存儲實現(xiàn)支持Querydsl,你也可以使用生成的元模型類型來定義排序表達式。

例7 通過使用Querydsl API定義排序表達式

QSort sort = QSort.by(QPerson.firstname.asc())
  .and(QSort.by(QPerson.lastname.desc()));

6.限制查詢結果

你可以通過使用first或top關鍵字來限制查詢方法的結果,這兩個關鍵字可以互換使用。你可以在top或first后面附加一個可選的數(shù)值,以指定要返回的最大結果大小。如果不加數(shù)字,就會假定結果大小為1。下面的例子顯示了如何限制查詢的大小。

例8. 用Top和First限制查詢結果的大小

User findFirstByOrderByLastnameAsc();
User findTopByOrderByAgeDesc();

Page<User> queryFirst10ByLastname(String lastname, Pageable pageable);
Slice<User> findTop3ByLastname(String lastname, Pageable pageable);
List<User> findFirst10ByLastname(String lastname, Sort sort);
List<User> findTop10ByLastname(String lastname, Pageable pageable);

對于支持不同查詢的數(shù)據(jù)集,限制表達式也支持Distinct關鍵字。另外,對于將結果集限制為一個實例的查詢,支持用Optional關鍵字將結果包入。

如果分頁或切片應用于限制性查詢的分頁(以及可用頁數(shù)的計算),則會在限制性結果內(nèi)應用。

通過使用排序參數(shù)將結果與動態(tài)排序相結合,可以讓你表達對 "K "最小元素和 "K "最大元素的查詢方法。

7. repository方法返回Collections or Iterables

當查詢方法返回多個結果時,可以使用標準的Java Iterable、List和Set來接受返回結果。除此之外,我們還支持返回Spring Data的Streamable,這是Iterable的一個自定義擴展,以及Vavr提供的集合類型。請參考附錄中對所有可能的查詢方法返回類型的解釋。

例9 使用Streamable作為查詢方法的返回類型

interface PersonRepository extends Repository<Person, Long> {
Streamable`<Person>` findByFirstnameContaining(String firstname);
Streamable`<Person>` findByLastnameContaining(String lastname);
}

Streamable `<Person>` result = repository.findByFirstnameContaining("av")
.and(repository.findByLastnameContaining("ea"));

例10 返回類型為自定義的Streamable包裝類

Streamable包裝類是為集合類提供的一種特殊的封裝類型, 是一種常用的模式,為返回多個元素的查詢結果提供API。通常,這些類型是通過調(diào)用返回類似集合類型的repository方法,并手動創(chuàng)建包裝器類型的實例來使用。你可以避免這個額外的步驟,因為Spring Data允許你使用這些包裝器類型作為查詢方法的返回類型,如果它們滿足以下條件:

  • 該類型實現(xiàn)了Streamable。
  • 該類型暴露了一個構造函數(shù)或一個名為of(…)或valueOf(…)的靜態(tài)工廠方法,它將Streamable作為參數(shù)。

下面的列表顯示了一個例子。

class Product {                                       
  MonetaryAmount getPrice() { … }
}

@RequiredArgsConstructor(staticName = "of")
class Products implements Streamable<Product> {       

  private final Streamable<Product> streamable;

  public MonetaryAmount getTotal() {                  
    return streamable.stream()
      .map(Priced::getPrice)
      .reduce(Money.of(0), MonetaryAmount::add);
  }


  @Override
  public Iterator<Product> iterator() {               
    return streamable.iterator();
  }
}

interface ProductRepository implements Repository<Product, Long> {
  Products findAllByDescriptionContaining(String text); 
}

一個Product實體類對象暴露了訪問產(chǎn)品價格的API。

一個Streamable<Product>的封裝類型,可以通過使用Products.of(…)(用Lombok注解創(chuàng)建的工廠方法)構建。使用Streamable<Product>的標準構造函數(shù)也可以做到。

封裝類型暴露了一個額外的API,計算Streamable<Product>上的新值。

實現(xiàn)Streamable接口并委托給實際結果。

那個包裝類型的Products可以直接作為查詢方法的返回類型使用。你不需要返回Streamable<Product>并在版本庫客戶端的查詢后手動包裝它。
對于Vavr類型集合的支持

Vavr是一個擁抱Java中函數(shù)式編程概念的庫。它帶有一組自定義的集合類型,你可以將其作為查詢方法的返回類型,如下表所示。

Vavr 集合類被使用的Vavr 實現(xiàn)類有效的Java源類型
io.vavr.collection.Seqio.vavr.collection.Listjava.util.Iterable
io.vavr.collection.Setio.vavr.collection.LinkedHashSetjava.util.Iterable
io.vavr.collection.Mapio.vavr.collection.LinkedHashMapjava.util.Map

你可以使用第一列中的類型(或其子類型)作為查詢方法的返回類型,并根據(jù)實際查詢結果的Java類型(第三列),獲得第二列中的類型作為實現(xiàn)類型使用。

或者,你可以聲明Traversable(相當于Vavr Iterable),然后我們從實際返回值中派生出實現(xiàn)類。也就是說,java.util.List會變成Vavr List或Seq,java.util.Set會變成Vavr LinkedHashSet Set,以此類推。

8.repository方法處理Null

從Spring Data 2.0開始,返回單個聚合實例的存儲庫CRUD方法使用Java 8的Optional來處理空值。除此之外,Spring Data還支持在查詢方法上返回以下封裝類型。

  • com.google.common.base.Optional
  • scala.Option
  • io.vavr.control.Option

另外,查詢方法可以選擇完全不使用包裝類型。沒有查詢結果會通過返回null來表示。Repository 方法返回集合、集合替代物、包裝器和流,保證不會返回 null,而是返回相應的空表示。詳見 “Repository 查詢返回類型”。

注解處理Null

你可以通過使用Spring Framework的nullability注解來表達repository方法的nullability約束。它們提供了一種工具友好的方法,并在運行時選擇加入空值檢查,如下所示。

  • @NonNullApi: 在包的層面上使用,聲明參數(shù)和返回值的默認行為分別是不接受也不產(chǎn)生空值。
  • @NonNull。用于不得為空的參數(shù)或返回值(在適用@NonNullApi的參數(shù)和返回值上不需要)。
  • @Nullable。用在可以為空的參數(shù)或返回值上。

Spring注解是用JSR 305注解(一個休眠但廣泛使用的JSR)進行元注解的。JSR 305元注釋讓工具供應商(如IDEA、Eclipse和Kotlin)以通用的方式提供null-safety支持,而無需對Spring注釋進行硬編碼支持。為了在運行時檢查查詢方法的無效性約束,你需要通過在package-info.java中使用Spring的@NonNullApi,在包級別上激活無效性,如下例所示。

例11 在 package-info.java中聲明Non-nullability

@org.springframework.lang.NonNullApi
package com.acme;

一旦非空默認到位,repository的查詢方法調(diào)用就會在運行時被驗證是否有空值約束。如果查詢結果違反了定義的約束,就會拋出一個異常。這種情況發(fā)生在方法會返回null,但被聲明為non-nullable(在版本庫所在的包上定義注解的默認值)。如果你想再次選擇加入可歸零的結果,可以有選擇地在個別方法上使用@Nullable。使用本節(jié)開頭提到的結果封裝類型繼續(xù)按預期工作:一個空的結果被翻譯成代表不存在的值。

下面的例子展示了剛才描述的一些技術。

例12. 使用不同的無效性約束

package com.acme;                                                 
import org.springframework.lang.Nullable;

interface UserRepository extends Repository<User, Long> {
  User getByEmailAddress(EmailAddress emailAddress);              
  @Nullable
  User findByEmailAddress(@Nullable EmailAddress emailAdress);    
  Optional<User> findOptionalByEmailAddress(EmailAddress emailAddress); 
}

repository駐留在一個包(或子包)中,我們?yōu)槠涠x了非空的行為。

當查詢沒有產(chǎn)生結果時,拋出一個EmptyResultDataAccessException。

當交給該方法的emailAddress為空時,拋出一個IllegalArgumentException。

當查詢沒有產(chǎn)生結果時,返回null。也接受null作為emailAddress的值。

當查詢沒有產(chǎn)生結果時返回Optional.empty()。當交給該方法的emailAddress為null時,拋出一個IllegalArgumentException。

9.查詢結果流

你可以通過使用Java 8 Stream <T>作為返回類型來增量地處理查詢方法的結果。如下面的例子所示,不把查詢結果包裹在Stream中,而是使用數(shù)據(jù)存儲的特定方法來執(zhí)行流式處理。

例13 用Java 8 Stream <T>串聯(lián)查詢的結果

@Query("select u from User u")
Stream<User> findAllByCustomQueryAndStream();

Stream<User> readAllByFirstnameNotNull();

@Query("select u from User u")
Stream<User> streamAllPaged(Pageable pageable);

一個流可能包裹了底層數(shù)據(jù)存儲的特定資源,因此,在使用后必須關閉。你可以通過使用close()方法來手動關閉Stream,或者使用Java 7 try-with-resources塊來關閉,如下面的例子中所示。

例14 在 try-with-resources 塊中處理一個 Stream <T> 的結果

try (Stream<User> stream = repository.findAllByCustomQueryAndStream()) {
  stream.forEach(…);
}

目前并非所有的Spring Data模塊都支持Stream <T>作為返回類型。

10.異步查詢結果

你可以通過使用Spring的異步方法運行能力來異步運行repository查詢。這意味著該方法在調(diào)用后立即返回,而實際的查詢發(fā)生在一個已經(jīng)提交給Spring TaskExecutor的任務中。異步查詢與反應式查詢不同,不應混合使用。關于響應式支持的更多細節(jié),請參見store-specific文檔。下面的例子顯示了一些異步查詢的情況。

例15. 異步查詢結果

@Async
Future<User> findByFirstname(String firstname);         

@Async
CompletableFuture<User> findOneByFirstname(String firstname); 

@Async
ListenableFuture<User> findOneByLastname(String lastname);  

使用java.util.concurrent.Future作為返回類型。

使用Java 8 java.util.concurrent.CompletableFuture作為返回類型。

使用org.springframework.util.concurrent.ListenableFuture作為返回類型。

以上就是詳解Spring Data JPA中Repository的接口查詢方法的詳細內(nèi)容,更多關于Repository接口查詢的資料請關注腳本之家其它相關文章!

相關文章

  • Java使用建造者模式實現(xiàn)辦理手機套餐功能詳解

    Java使用建造者模式實現(xiàn)辦理手機套餐功能詳解

    這篇文章主要介紹了Java使用建造者模式實現(xiàn)辦理手機套餐功能,較為詳細的描述了建造者模式的概念、原理并結合實例形式分析了Java使用建造者模式實現(xiàn)的辦理手機套餐功能具體步驟與相關操作注意事項,需要的朋友可以參考下
    2018-05-05
  • Maven實戰(zhàn)之搭建Maven私服和鏡像的方法(圖文)

    Maven實戰(zhàn)之搭建Maven私服和鏡像的方法(圖文)

    本篇文章主要介紹了搭建Maven私服和鏡像的方法(圖文),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-12-12
  • 使用spring boot通過自定義注解打印所需日志

    使用spring boot通過自定義注解打印所需日志

    這篇文章主要介紹了使用spring boot通過自定義注解打印所需日志的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • Java計算代碼段執(zhí)行時間的詳細過程

    Java計算代碼段執(zhí)行時間的詳細過程

    java里計算代碼段執(zhí)行時間可以有兩種方法,一種是毫秒級別的計算,另一種是更精確的納秒級別的計算,這篇文章主要介紹了java計算代碼段執(zhí)行時間,需要的朋友可以參考下
    2023-02-02
  • MyBatis中map的應用與模糊查詢實現(xiàn)代碼

    MyBatis中map的應用與模糊查詢實現(xiàn)代碼

    這篇文章主要介紹了MyBatis中map的應用與模糊查詢實現(xiàn)代碼,文中通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-11-11
  • 基于redis key占用內(nèi)存量分析

    基于redis key占用內(nèi)存量分析

    這篇文章主要介紹了基于redis key占用內(nèi)存量分析,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-11-11
  • springboot如何解決跨域后session獲取不到sessionId不一致

    springboot如何解決跨域后session獲取不到sessionId不一致

    這篇文章主要介紹了springboot如何解決跨域后session獲取不到sessionId不一致問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • Feign遠程調(diào)用Multipartfile參數(shù)處理

    Feign遠程調(diào)用Multipartfile參數(shù)處理

    這篇文章主要介紹了Feign遠程調(diào)用Multipartfile參數(shù)處理,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • 關于RequestMapping注解的作用說明

    關于RequestMapping注解的作用說明

    這篇文章主要介紹了關于RequestMapping注解的作用說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教。
    2022-01-01
  • FineReport中自定義登錄界面的方法

    FineReport中自定義登錄界面的方法

    這篇文章主要介紹了 FineReport中自定義登錄界面的方法,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2017-03-03

最新評論