查询方法
您通常在存储库上触发的大多数数据访问作都会导致对数据库运行查询。 定义这样的查询是在存储库接口上声明一个方法的问题,如以下示例所示:
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将偏移量和排序参数传递给数据库。 |
| 4 | 为给定条件查找单个实体。
它完成为IncorrectResultSizeDataAccessException在非唯一结果上。 |
| 5 | 除非 <4>,否则即使查询产生更多结果行,也始终发出第一个实体。 |
| 6 | 这findByLastname方法显示对具有给定姓氏的所有人员的查询。 |
| 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 | 使用返回类型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 Repositories 的自定义实现中描述的工具来添加自定义修改行为。
用@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);
此表达式支持可通过查询 SPI 进行扩展:org.springframework.data.spel.spi.EvaluationContextExtension.
查询 SPI 可以提供属性和函数,并可以自定义根对象。
在构建查询时,在 SpEL 评估时从应用程序上下文中检索扩展。
| 当将 SpEL 表达式与纯参数结合使用时,请使用命名参数表示法而不是本机绑定标记,以确保正确的绑定顺序。 |
使用表达式的另一种方法是在查询中间,与参数无关。 计算查询的结果将替换查询字符串中的表达式。
@Query("SELECT * FROM #{#tableName} WHERE lastname = :lastname")
Flux<Person> findByQueryWithExpression(String lastname);
它在第一次执行之前评估一次,并使用StandardEvaluationContext与两个变量tableName和qualifiedTableName添加。
当表名本身是动态的时,这种用法最有用,因为它们也使用 SpEL 表达式。
查询字符串中的 SpEL 可能是增强查询的有效方法。 但是,他们也可以接受各种不需要的论点。 应确保在将字符串传递给查询之前对其进行清理,以避免对查询进行不必要的更改。