此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 Spring Data Relational 3.4.0! |
查询方法
您通常在存储库上触发的大多数数据访问作都会导致对数据库运行查询。 定义此类查询就是在存储库接口上声明方法,如下例所示:
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 | 该方法显示具有给定firstname 一旦firstname 由给定的Publisher . |
3 | 用Pageable 将 offset 和 sorting 参数传递给数据库。 |
4 | 为给定条件查找单个实体。
它以IncorrectResultSizeDataAccessException 在非唯一结果上。 |
5 | 除非 <4>,否则即使查询生成更多结果行,也始终会发出第一个实体。 |
6 | 这findByLastname method 显示具有给定姓氏的所有人员的查询。 |
7 | 对单个Person 仅实体投影firstname 和lastname 列。
带注释的查询使用本机绑定标记,在此示例中是 Postgres 绑定标记。 |
请注意,在@Query
注解必须与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 | 使用 return type 为Mono<Integer> 返回受影响的行数。 |
2 | 用Void 仅报告是否成功删除了行,而不发出 Result 值。 |
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 Repositories 的自定义实现中描述的工具来添加自定义修改行为。
用@Query
以下示例演示如何使用@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 compiler 标志。
通过在构建中使用此标志作为调试信息的替代方法,您可以省略@Param 注解。 |
使用 SPEL 表达式的查询
查询字符串定义可以与 SPEL 表达式一起使用,以在运行时创建动态查询。 SPEL 表达式可以通过两种方式使用。
SPEL 表达式可以提供谓词值,这些值在运行查询之前进行评估。
表达式通过包含所有参数的数组公开方法参数。
以下查询使用[0]
声明 的谓词值lastname
(相当于:lastname
参数绑定):
@Query("SELECT * FROM person WHERE lastname = :#{[0]}")
Flux<Person> findByQueryWithParameterExpression(String lastname);
此 Expression 支持可通过 Query SPI 进行扩展:org.springframework.data.spel.spi.EvaluationContextExtension
.
Query SPI 可以提供属性和函数,并且可以自定义根对象。
在构建查询时,在 SPEL 评估时从应用程序上下文中检索扩展。
将 SPEL 表达式与普通参数结合使用时,请使用命名参数表示法而不是本机绑定标记,以确保正确的绑定顺序。 |
使用 Expression 的另一种方法是在 query 中间,独立于参数。 评估查询的结果将替换查询字符串中的表达式。
@Query("SELECT * FROM #{tableName} WHERE lastname = :lastname")
Flux<Person> findByQueryWithExpression(String lastname);
它在第一次执行之前评估一次,并使用StandardEvaluationContext
替换为两个变量tableName
和qualifiedTableName
添加。
当 table 名本身是动态的时,这种用法最有用,因为它们也使用 SPEL 表达式。
查询字符串中的 SPEL 可以成为增强查询的有效方法。 但是,他们也可以接受各种不需要的论点。 在将字符串传递给查询之前,应确保对字符串进行清理,以避免对查询进行不必要的更改。