查询方法

本节提供了有关 Spring Data JDBC 的实现和使用的一些具体信息。spring-doc.cadn.net.cn

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

PersonRepository 与查询方法
interface PersonRepository extends PagingAndSortingRepository<Person, String> {

  List<Person> findByFirstname(String firstname);                                   (1)

  List<Person> findByFirstnameOrderByLastname(String firstname, Pageable pageable); (2)

  Slice<Person> findByLastname(String lastname, Pageable pageable);                 (3)

  Page<Person> findByLastname(String lastname, Pageable pageable);                  (4)

  Person findByFirstnameAndLastname(String firstname, String lastname);             (5)

  Person findFirstByLastname(String lastname);                                      (6)

  @Query("SELECT * FROM person WHERE lastname = :lastname")
  List<Person> findByLastname(String lastname);                                     (7)
  @Query("SELECT * FROM person WHERE lastname = :lastname")
  Stream<Person> streamByLastname(String lastname);                                     (8)

  @Query("SELECT * FROM person WHERE username = :#{ principal?.username }")
  Person findActiveUser();															(9)
}
1 该方法显示具有给定firstname. 查询是通过解析可与AndOr. 因此,方法名称会生成SELECT … FROM person WHERE firstname = :firstname.
2 Pageable将 offset 和 sorting 参数传递给数据库。
3 返回一个Slice<Person>.选择LIMIT+1rows 来确定是否有更多数据可供使用。ResultSetExtractor不支持自定义。
4 运行分页查询,返回Page<Person>.仅选择给定页面边界内的数据,并可能选择计数查询来确定总计数。ResultSetExtractor不支持自定义。
5 为给定条件查找单个实体。 它以IncorrectResultSizeDataAccessException在非唯一结果上。
6 与 <3> 相比,即使查询生成更多结果文档,也始终会发出第一个实体。
7 findByLastnamemethod 显示具有给定lastname.
8 streamByLastnamemethod 返回一个Stream,这使得值在从数据库返回后立即成为可能。
9 您可以使用 Spring 表达式语言动态解析参数。 在该示例中,使用 Spring Security 解析当前用户的用户名。

下表显示了查询方法支持的关键字: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

查询派生仅限于可在WHERE子句。

查询查找策略

JDBC 模块支持在@Queryannotation 或作为命名查询。spring-doc.cadn.net.cn

从方法名称派生查询目前仅限于简单属性,即直接存在于聚合根中的属性。 此外,此方法仅支持 select 查询。spring-doc.cadn.net.cn

@Query

以下示例演示如何使用@Query要声明 Query 方法:spring-doc.cadn.net.cn

使用 @Query 声明查询方法
interface UserRepository extends CrudRepository<User, Long> {

  @Query("select firstName, lastName from User u where u.emailAddress = :email")
  User findByEmailAddress(@Param("email") String email);
}

要将查询结果转换为相同的实体RowMapper默认用于 Spring Data JDBC 自身生成的查询。 您提供的查询必须与RowMapper预计。 必须提供实体的构造函数中使用的所有属性的列。 通过 setter、wither 或 field 访问设置的属性列是可选的。 不会设置结果中没有匹配列的属性。 该查询用于填充聚合根、嵌入实体和一对一关系,包括作为 SQL 数组类型存储和加载的基元类型数组。 为 map、list、sets 和 arrays 的实体生成单独的查询。spring-doc.cadn.net.cn

属性一对一关系必须具有以关系名称加 为前缀的 name 。 例如,如果_User在上面的示例中,有一个address与属性city该列city必须贴标签address_city.spring-doc.cadn.net.cn

请注意,基于字符串的查询不支持分页,也不接受Sort,PageRequestLimit作为查询参数,对于这些查询,需要重写查询。 如果要应用限制,请使用 SQL 表达此意图,并自行将相应的参数绑定到查询。

查询可能包含 SPEL 表达式。 有两种变体的评估方式不同。spring-doc.cadn.net.cn

在第一个变体中,SPEL 表达式的前缀为:并像 BIND 变量一样使用。 这样的 SPEL 表达式将被绑定变量替换,并且该变量将绑定到 SPEL 表达式的结果。spring-doc.cadn.net.cn

在查询中使用 SPEL
@Query("SELECT * FROM person WHERE id = :#{#person.id}")
Person findWithSpEL(PersonRef person);

这可用于访问参数的成员,如上面的示例所示。 有关更多涉及的使用案例,请参阅EvaluationContextExtension可以在应用程序上下文中可用,而应用程序上下文又可以使任何对象可用于 SPEL。spring-doc.cadn.net.cn

另一个变体可以在查询中的任何位置使用,并且评估查询的结果将替换查询字符串中的表达式。spring-doc.cadn.net.cn

在查询中使用 SPEL
@Query("SELECT * FROM #{tableName} WHERE id = :id")
Person findWithSpEL(PersonRef person);

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

Spring 完全支持 Java 8 的参数名称发现,基于-parameterscompiler 标志。 通过在构建中使用此标志作为调试信息的替代方法,您可以省略@Param注解。
Spring Data JDBC 仅支持命名参数。

命名查询

如果 Comments 中没有给出查询,如上一节所述,Spring Data JDBC 将尝试查找命名查询。 有两种方法可以确定查询的名称。 默认情况下,采用查询的 domain 类,即存储库的聚合根,采用其简单名称,并附加由分隔.. 或者,@Queryannotation 具有name属性,该属性可用于指定要查找的查询的名称。spring-doc.cadn.net.cn

命名查询应在属性文件中提供META-INF/jdbc-named-queries.properties在 Classpath 上。spring-doc.cadn.net.cn

可以通过将值设置为@EnableJdbcRepositories.namedQueriesLocation.spring-doc.cadn.net.cn

命名查询的处理方式与 annotation 提供的查询相同。spring-doc.cadn.net.cn

自定义查询方法

流式处理结果

当您指定 Stream 作为查询方法的返回类型时, Spring Data JDBC 会在元素可用后立即返回这些元素。 在处理大量数据时,这适用于减少延迟和内存需求。spring-doc.cadn.net.cn

流包含与数据库的开放连接。 为避免内存泄漏,最终需要通过关闭流来关闭该连接。 推荐的方法是try-with-resource clause. 这也意味着,一旦关闭了与数据库的连接,流就无法获取更多元素,并可能引发异常。spring-doc.cadn.net.cn

习惯RowMapperResultSetExtractor

@Queryannotation 允许您指定自定义RowMapperResultSetExtractor使用。 属性rowMapperClassresultSetExtractorClass允许您指定要使用的类,这些类将使用默认构造函数进行实例化。 或者,您可以将rowMapperClassRefresultSetExtractorClassRef添加到 Spring 应用程序上下文中的 bean 名称。spring-doc.cadn.net.cn

如果您想使用某个RowMapper不仅适用于单个方法,还适用于自定义查询返回特定类型的所有方法, 您可以注册一个RowMapperMapbean 并注册一个RowMapperper 方法返回类型。 以下示例演示如何注册DefaultQueryMappingConfiguration:spring-doc.cadn.net.cn

@Bean
QueryMappingConfiguration rowMappers() {
  return new DefaultQueryMappingConfiguration()
    .register(Person.class, new PersonRowMapper())
    .register(Address.class, new AddressRowMapper());
}

确定哪个RowMapper要使用 for 方法,请根据方法的返回类型执行以下步骤:spring-doc.cadn.net.cn

  1. 如果类型是简单类型,则没有RowMapper被使用。spring-doc.cadn.net.cn

    相反,查询应返回具有单个列的单个行,并且对该值应用到返回类型的转换。spring-doc.cadn.net.cn

  2. QueryMappingConfiguration进行迭代,直到找到一个是相关返回类型的超类或接口。 这RowMapperregistered for that class 的 。spring-doc.cadn.net.cn

    迭代按照注册的顺序进行,因此请确保在特定类型之后注册更通用的类型。spring-doc.cadn.net.cn

如果适用,包装器类型(如 collections 或Optional解包。 因此,返回类型Optional<Person>使用Persontype 在前面的进程中。spring-doc.cadn.net.cn

使用自定义RowMapper通过QueryMappingConfiguration,@Query(rowMapperClass=…)或自定义ResultSetExtractor禁用 Entity Callbacks 和 Lifecycle Events,因为结果映射可以根据需要发出自己的事件/回调。

修改查询

您可以使用@Modifyingon query 方法,如下例所示:spring-doc.cadn.net.cn

@Modifying
@Query("UPDATE DUMMYENTITY SET name = :name WHERE id = :id")
boolean updateName(@Param("id") Long id, @Param("name") String name);

您可以指定以下返回类型:spring-doc.cadn.net.cn

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