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

查询方法

您通常在存储库上触发的大多数数据访问作都会导致对数据库运行查询。 定义此类查询就是在存储库接口上声明方法,如下例所示:spring-doc.cadn.net.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 该方法显示具有给定firstname. 查询是通过解析可与AndOr. 因此,方法名称会生成SELECT … FROM person WHERE firstname = :firstname.
2 该方法显示具有给定firstname一旦firstname由给定的Publisher.
3 Pageable将 offset 和 sorting 参数传递给数据库。
4 为给定条件查找单个实体。 它以IncorrectResultSizeDataAccessException在非唯一结果上。
5 除非 <4>,否则即使查询生成更多结果行,也始终会发出第一个实体。
6 findByLastnamemethod 显示具有给定姓氏的所有人员的查询。
7 对单个Person仅实体投影firstnamelastname列。 带注释的查询使用本机绑定标记,在此示例中是 Postgres 绑定标记。

请注意,在@Query注解必须与NamingStrategy对于相应的属性。 如果 select 语句不包含匹配的列,则不会设置该属性。 如果持久性构造函数需要该属性,则为 null 或(对于基元类型)提供默认值。spring-doc.cadn.net.cn

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

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

Afterspring-doc.cadn.net.cn

findByBirthdateAfter(Date date)spring-doc.cadn.net.cn

birthdate > datespring-doc.cadn.net.cn

GreaterThanspring-doc.cadn.net.cn

findByAgeGreaterThan(int age)spring-doc.cadn.net.cn

age > agespring-doc.cadn.net.cn

GreaterThanEqualspring-doc.cadn.net.cn

findByAgeGreaterThanEqual(int age)spring-doc.cadn.net.cn

age >= agespring-doc.cadn.net.cn

Beforespring-doc.cadn.net.cn

findByBirthdateBefore(Date date)spring-doc.cadn.net.cn

birthdate < datespring-doc.cadn.net.cn

LessThanspring-doc.cadn.net.cn

findByAgeLessThan(int age)spring-doc.cadn.net.cn

age < agespring-doc.cadn.net.cn

LessThanEqualspring-doc.cadn.net.cn

findByAgeLessThanEqual(int age)spring-doc.cadn.net.cn

age <= agespring-doc.cadn.net.cn

Betweenspring-doc.cadn.net.cn

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

age BETWEEN from AND tospring-doc.cadn.net.cn

NotBetweenspring-doc.cadn.net.cn

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

age NOT BETWEEN from AND tospring-doc.cadn.net.cn

Inspring-doc.cadn.net.cn

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

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

NotInspring-doc.cadn.net.cn

findByAgeNotIn(Collection ages)spring-doc.cadn.net.cn

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

IsNotNull,NotNullspring-doc.cadn.net.cn

findByFirstnameNotNull()spring-doc.cadn.net.cn

firstname IS NOT NULLspring-doc.cadn.net.cn

IsNull,Nullspring-doc.cadn.net.cn

findByFirstnameNull()spring-doc.cadn.net.cn

firstname IS NULLspring-doc.cadn.net.cn

Like,StartingWith,EndingWithspring-doc.cadn.net.cn

findByFirstnameLike(String name)spring-doc.cadn.net.cn

firstname LIKE namespring-doc.cadn.net.cn

NotLike,IsNotLikespring-doc.cadn.net.cn

findByFirstnameNotLike(String name)spring-doc.cadn.net.cn

firstname NOT LIKE namespring-doc.cadn.net.cn

Containing在字符串上spring-doc.cadn.net.cn

findByFirstnameContaining(String name)spring-doc.cadn.net.cn

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

NotContaining在字符串上spring-doc.cadn.net.cn

findByFirstnameNotContaining(String name)spring-doc.cadn.net.cn

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

(No keyword)spring-doc.cadn.net.cn

findByFirstname(String name)spring-doc.cadn.net.cn

firstname = namespring-doc.cadn.net.cn

Notspring-doc.cadn.net.cn

findByFirstnameNot(String name)spring-doc.cadn.net.cn

firstname != namespring-doc.cadn.net.cn

IsTrue,Truespring-doc.cadn.net.cn

findByActiveIsTrue()spring-doc.cadn.net.cn

active IS TRUEspring-doc.cadn.net.cn

IsFalse,Falsespring-doc.cadn.net.cn

findByActiveIsFalse()spring-doc.cadn.net.cn

active IS FALSEspring-doc.cadn.net.cn

修改查询

前面的部分介绍了如何声明查询以访问给定的实体或实体集合。 使用上表中的关键字可以与delete…Byremove…By创建删除匹配行的派生查询。spring-doc.cadn.net.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 使用 return type 为Mono<Integer>返回受影响的行数。
2 Void仅报告是否成功删除了行,而不发出 Result 值。
3 Boolean报告是否至少删除了一行。

由于这种方法对于全面的自定义功能是可行的,因此您可以通过使用@Modifying,如以下示例所示:spring-doc.cadn.net.cn

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

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

@Modifying注解仅与@Query注解。 派生的自定义方法不需要此注释。spring-doc.cadn.net.cn

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

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

@Query

以下示例演示如何使用@Query要声明 Query 方法:spring-doc.cadn.net.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);
}
请注意,基于字符串的查询不支持分页,也不接受Sort,PageRequestLimit作为查询参数,对于这些查询,需要重写查询。 如果要应用限制,请使用 SQL 表达此意图,并自行将相应的参数绑定到查询。
Spring 完全支持 Java 8 的参数名称发现,基于-parameterscompiler 标志。 通过在构建中使用此标志作为调试信息的替代方法,您可以省略@Param注解。

使用 SPEL 表达式的查询

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

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

表达式通过包含所有参数的数组公开方法参数。 以下查询使用[0]声明 的谓词值lastname(相当于:lastname参数绑定):spring-doc.cadn.net.cn

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

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

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

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

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

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

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