此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 Spring Data Relational 3.4.0spring-doc.cn

查询方法

您通常在存储库上触发的大多数数据访问操作都会导致对数据库运行查询。 定义此类查询就是在存储库接口上声明方法,如下例所示:spring-doc.cn

示例 1.PersonRepository 与查询方法
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 该方法显示具有给定 . 查询是通过解析可与 和 连接的约束的方法名称来派生的。 因此,方法名称会导致查询表达式 。firstnameAndOrSELECT … FROM person WHERE firstname = :firstname
2 一旦给定的 .firstnamefirstnamePublisher
3 用于将 offset 和 sorting 参数传递到数据库。Pageable
4 为给定条件查找单个实体。 它以非唯一结果结束。IncorrectResultSizeDataAccessException
5 除非 <4>,否则即使查询生成更多结果行,也始终会发出第一个实体。
6 该方法显示具有给定姓氏的所有人员的查询。findByLastname
7 对仅投影和列的单个实体的查询。 带注释的查询使用本机绑定标记,在此示例中是 Postgres 绑定标记。Personfirstnamelastname

请注意,注释中使用的 select 语句的列必须与 为相应属性生成的名称匹配。 如果 select 语句不包含匹配的列,则不会设置该属性。 如果持久性构造函数需要该属性,则为 null 或(对于基元类型)提供默认值。@QueryNamingStrategyspring-doc.cn

下表显示了查询方法支持的关键字:spring-doc.cn

表 1.查询方法支持的关键字
关键词 样本 逻辑结果

Afterspring-doc.cn

findByBirthdateAfter(Date date)spring-doc.cn

birthdate > datespring-doc.cn

GreaterThanspring-doc.cn

findByAgeGreaterThan(int age)spring-doc.cn

age > agespring-doc.cn

GreaterThanEqualspring-doc.cn

findByAgeGreaterThanEqual(int age)spring-doc.cn

age >= agespring-doc.cn

Beforespring-doc.cn

findByBirthdateBefore(Date date)spring-doc.cn

birthdate < datespring-doc.cn

LessThanspring-doc.cn

findByAgeLessThan(int age)spring-doc.cn

age < agespring-doc.cn

LessThanEqualspring-doc.cn

findByAgeLessThanEqual(int age)spring-doc.cn

age <= agespring-doc.cn

Betweenspring-doc.cn

findByAgeBetween(int from, int to)spring-doc.cn

age BETWEEN from AND tospring-doc.cn

NotBetweenspring-doc.cn

findByAgeNotBetween(int from, int to)spring-doc.cn

age NOT BETWEEN from AND tospring-doc.cn

Inspring-doc.cn

findByAgeIn(Collection<Integer> ages)spring-doc.cn

age IN (age1, age2, ageN)spring-doc.cn

NotInspring-doc.cn

findByAgeNotIn(Collection ages)spring-doc.cn

age NOT IN (age1, age2, ageN)spring-doc.cn

IsNotNull,NotNullspring-doc.cn

findByFirstnameNotNull()spring-doc.cn

firstname IS NOT NULLspring-doc.cn

IsNull,Nullspring-doc.cn

findByFirstnameNull()spring-doc.cn

firstname IS NULLspring-doc.cn

Like, ,StartingWithEndingWithspring-doc.cn

findByFirstnameLike(String name)spring-doc.cn

firstname LIKE namespring-doc.cn

NotLike,IsNotLikespring-doc.cn

findByFirstnameNotLike(String name)spring-doc.cn

firstname NOT LIKE namespring-doc.cn

Containing在字符串上spring-doc.cn

findByFirstnameContaining(String name)spring-doc.cn

firstname LIKE '%' + name +'%'spring-doc.cn

NotContaining在字符串上spring-doc.cn

findByFirstnameNotContaining(String name)spring-doc.cn

firstname NOT LIKE '%' + name +'%'spring-doc.cn

(No keyword)spring-doc.cn

findByFirstname(String name)spring-doc.cn

firstname = namespring-doc.cn

Notspring-doc.cn

findByFirstnameNot(String name)spring-doc.cn

firstname != namespring-doc.cn

IsTrue,Truespring-doc.cn

findByActiveIsTrue()spring-doc.cn

active IS TRUEspring-doc.cn

IsFalse,Falsespring-doc.cn

findByActiveIsFalse()spring-doc.cn

active IS FALSEspring-doc.cn

修改查询

前面的部分介绍了如何声明查询以访问给定的实体或实体集合。 使用上表中的关键字可以与 OR 结合使用,以创建删除匹配行的派生查询。delete…Byremove…Byspring-doc.cn

示例 2. 查询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 使用返回类型 of 返回受影响的行数。Mono<Integer>
2 Using only 报告是否成功删除了行,而不发出结果值。Void
3 Using 报告是否至少删除了一行。Boolean

由于此方法对于全面的自定义功能是可行的,因此您可以通过使用注释查询方法来修改只需要参数绑定的查询,如以下示例所示:@Modifyingspring-doc.cn

@Modifying
@Query("UPDATE person SET firstname = :firstname where lastname = :lastname")
Mono<Integer> setFixedFirstnameFor(String firstname, String lastname);

修改查询的结果可以是:spring-doc.cn

  • Void(或 Kotlin )丢弃更新计数并等待完成。Unitspring-doc.cn

  • Integer或其他数字类型发出受影响的行数。spring-doc.cn

  • Boolean发出是否至少更新了一行。spring-doc.cn

注释仅与注释结合使用。 派生的自定义方法不需要此注释。@Modifying@Queryspring-doc.cn

修改查询直接针对数据库执行。 不会调用任何事件或回调。 因此,如果带有审核注释的字段未在带注释的查询中更新,则不会更新这些字段。spring-doc.cn

或者,您可以使用 Spring Data Repositories 的自定义实现中描述的工具来添加自定义修改行为。spring-doc.cn

@Query

以下示例演示如何使用 声明查询方法:@Queryspring-doc.cn

使用 @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);
}
请注意,基于字符串的查询不支持分页,也不接受 、 、 ,并且作为查询参数,对于这些查询,需要重写查询。 如果要应用限制,请使用 SQL 表达此意图,并自行将相应的参数绑定到查询。SortPageRequestLimit
Spring 完全支持基于 compiler 标志的 Java 8 参数名称发现。 通过在构建中使用此标志作为调试信息的替代方法,您可以省略命名参数的注释。-parameters@Param

使用 SPEL 表达式的查询

查询字符串定义可以与 SPEL 表达式一起使用,以在运行时创建动态查询。 SPEL 表达式可以通过两种方式使用。spring-doc.cn

SPEL 表达式可以提供谓词值,这些值在运行查询之前进行评估。spring-doc.cn

表达式通过包含所有参数的数组公开方法参数。 以下查询用于声明 (的谓词值 (等效于参数 binding):[0]lastname:lastnamespring-doc.cn

@Query("SELECT * FROM person WHERE lastname = :#{[0]}")
Flux<Person> findByQueryWithParameterExpression(String lastname);

此 Expression 支持可通过查询 SPI: 进行扩展。 Query SPI 可以提供属性和函数,并且可以自定义根对象。 在构建查询时,在 SPEL 评估时从应用程序上下文中检索扩展。org.springframework.data.spel.spi.EvaluationContextExtensionspring-doc.cn

将 SPEL 表达式与普通参数结合使用时,请使用命名参数表示法而不是本机绑定标记,以确保正确的绑定顺序。

使用 Expression 的另一种方法是在 query 中间,独立于参数。 评估查询的结果将替换查询字符串中的表达式。spring-doc.cn

在查询中使用 SPEL
@Query("SELECT * FROM #{tableName} WHERE lastname = :lastname")
Flux<Person> findByQueryWithExpression(String lastname);

它在第一次执行之前评估一次,并使用带有两个变量的 a 并添加。 当 table 名本身是动态的时,这种用法最有用,因为它们也使用 SPEL 表达式。StandardEvaluationContexttableNamequalifiedTableNamespring-doc.cn

查询字符串中的 SPEL 可以成为增强查询的有效方法。 但是,他们也可以接受各种不需要的论点。 在将字符串传递给查询之前,应确保对字符串进行清理,以避免对查询进行不必要的更改。spring-doc.cn