查詢方法
您通常在 repository 上觸發的大部分資料存取操作,都會導致針對資料庫執行查詢。定義此類查詢就是在 repository 介面上宣告方法,如下例所示
interface ReactivePersonRepository extends ReactiveSortingRepository<Person, Long> {
Flux<Person> findByFirstname(String firstname); (1)
Flux<Person> findByFirstname(Publisher<String> firstname); (2)
Flux<Person> findByFirstnameOrderByLastname(String firstname, Pageable pageable); (3)
Mono<Person> findByFirstnameAndLastname(String firstname, String lastname); (4)
Mono<Person> findFirstByLastname(String lastname); (5)
@Query("SELECT * FROM person WHERE lastname = :lastname")
Flux<Person> findByLastname(String lastname); (6)
@Query("SELECT firstname, lastname FROM person WHERE lastname = $1")
Mono<Person> findFirstByLastname(String lastname); (7)
}
1 | 此方法顯示查詢所有具有給定 firstname 的人員。此查詢是透過解析方法名稱以取得可與 And 和 Or 串連的條件約束而衍生。因此,方法名稱會產生 SELECT … FROM person WHERE firstname = :firstname 的查詢表示式。 |
2 | 此方法顯示在給定的 Publisher 發出 firstname 後,查詢所有具有給定 firstname 的人員。 |
3 | 使用 Pageable 將偏移量和排序參數傳遞至資料庫。 |
4 | 尋找符合給定條件的單一實體。在非唯一結果上,它會以 IncorrectResultSizeDataAccessException 完成。 |
5 | 除非 <4>,否則即使查詢產生更多結果列,也始終會發出第一個實體。 |
6 | findByLastname 方法顯示查詢所有具有給定姓氏的人員。 |
7 | 針對單一 Person 實體的查詢,僅投影 firstname 和 lastname 欄位。帶註解的查詢使用原生繫結標記,在此範例中為 Postgres 繫結標記。 |
請注意,@Query
註解中使用的 select 陳述式的欄位必須符合 NamingStrategy
為各自屬性產生的名稱。如果 select 陳述式不包含相符的欄位,則不會設定該屬性。如果持久化建構子需要該屬性,則會提供 null 或(對於基本類型)預設值。
下表顯示查詢方法支援的關鍵字
關鍵字 | 範例 | 邏輯結果 |
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
修改查詢
先前的章節說明如何宣告查詢以存取給定的實體或實體集合。先前表格中的關鍵字可以與 delete…By
或 remove…By
結合使用,以建立衍生查詢,以刪除相符的列。
Delete…By
查詢interface ReactivePersonRepository extends ReactiveSortingRepository<Person, String> {
Mono<Integer> deleteByLastname(String lastname); (1)
Mono<Void> deletePersonByLastname(String lastname); (2)
Mono<Boolean> deletePersonByLastname(String lastname); (3)
}
1 | 使用 Mono<Integer> 的回傳類型會傳回受影響的列數。 |
2 | 使用 Void 僅報告列是否已成功刪除,而不會發出結果值。 |
3 | 使用 Boolean 報告是否已移除至少一列。 |
由於此方法適用於全面的自訂功能,因此您可以修改只需要參數繫結的查詢,方法是使用 @Modifying
註解查詢方法,如下例所示
@Modifying
@Query("UPDATE person SET firstname = :firstname where lastname = :lastname")
Mono<Integer> setFixedFirstnameFor(String firstname, String lastname);
修改查詢的結果可以是
-
Void
(或 KotlinUnit
) 以捨棄更新計數並等待完成。 -
Integer
或其他數值類型,發出受影響的列數。 -
Boolean
,以發出是否已更新至少一列。
@Modifying
註解僅與 @Query
註解結合使用時才相關。衍生的自訂方法不需要此註解。
修改查詢會直接針對資料庫執行。不會呼叫任何事件或回呼。因此,如果稽核註解的欄位未在帶註解的查詢中更新,則它們也不會更新。
或者,您可以使用 Spring Data Repository 的自訂實作 中描述的功能來新增自訂修改行為。
使用 @Query
以下範例示範如何使用 @Query
宣告查詢方法
interface UserRepository extends ReactiveCrudRepository<User, Long> {
@Query("select firstName, lastName from User u where u.emailAddress = :email")
Flux<User> findByEmailAddress(@Param("email") String email);
}
請注意,基於字串的查詢不支援分頁,也不接受 Sort 、PageRequest 和 Limit 作為查詢參數,因為對於這些查詢,將需要重寫查詢。如果您想要套用限制,請使用 SQL 表達此意圖,並自行將適當的參數繫結至查詢。 |
Spring 完全支援基於 Java 8 的 -parameters 編譯器旗標的參數名稱探索。透過在您的建置中使用此旗標作為偵錯資訊的替代方案,您可以省略具名參數的 @Param 註解。 |
使用 SpEL 表示式的查詢
查詢字串定義可以與 SpEL 表示式一起使用,以在執行階段建立動態查詢。SpEL 表示式可以透過兩種方式使用。
SpEL 表示式可以提供述詞值,這些值會在執行查詢之前立即評估。
表示式透過包含所有引數的陣列公開方法引數。以下查詢使用 [0]
來宣告 lastname
的述詞值(相當於 :lastname
參數繫結)
@Query("SELECT * FROM person WHERE lastname = :#{[0]}")
Flux<Person> findByQueryWithParameterExpression(String lastname);
此表示式支援可透過 Query SPI 擴充:org.springframework.data.spel.spi.EvaluationContextExtension
。Query SPI 可以貢獻屬性和函數,並且可以自訂根物件。擴充功能會在建置查詢時 SpEL 評估時從應用程式內容中擷取。
將 SpEL 表示式與純參數結合使用時,請使用具名參數標記法,而不是原生繫結標記,以確保正確的繫結順序。 |
使用表示式的另一種方式是在查詢的中間,獨立於參數。評估查詢的結果將取代查詢字串中的表示式。
@Query("SELECT * FROM #{tableName} WHERE lastname = :lastname")
Flux<Person> findByQueryWithExpression(String lastname);
它會在第一次執行之前評估一次,並使用新增了兩個變數 tableName
和 qualifiedTableName
的 StandardEvaluationContext
。當表名稱本身是動態的時,此用法最有用,因為它們也使用 SpEL 表示式。
查詢字串中的 SpEL 可以是增強查詢的強大方法。但是,它們也可能接受廣泛的不必要引數。您應確保在將字串傳遞至查詢之前對其進行清理,以避免對查詢進行不必要的變更。