查詢方法
您通常在倉庫上觸發的大多數資料訪問操作都會導致對資料庫執行查詢。定義此類查詢是在倉庫介面上宣告方法的問題,示例如下所示
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 倉庫的自定義實現中描述的功能來新增自定義修改行為。
使用@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 完全支援基於-parameters編譯器標誌的 Java 8 引數名稱發現。透過在您的構建中使用此標誌作為除錯資訊的替代方案,您可以省略命名引數的@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 可以是增強查詢的強大方式。然而,它們也可以接受廣泛的不需要的引數。您應該確保在將字串傳遞給查詢之前對其進行清理,以避免對查詢造成不必要的更改。