对于最新的稳定版本,请使用 Spring Data Relational 3.3.1Spring中文文档

对于最新的稳定版本,请使用 Spring Data Relational 3.3.1Spring中文文档

本节提供有关 Spring Data JDBC 的实现和使用的一些具体信息。Spring中文文档

通常在存储库上触发的大多数数据访问操作都会导致对数据库运行查询。 定义这样的查询是在存储库接口上声明方法的问题,如以下示例所示:Spring中文文档

具有查询方法的 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 该方法显示对具有给定 . 通过分析可与 和 连接的约束的方法名称来派生查询。 因此,方法名称将生成 .firstnameAndOrSELECT … FROM person WHERE firstname = :firstname
2 用于将偏移量和排序参数传递到数据库。Pageable
3 返回 .选择行以确定是否有更多数据可供使用。 不支持自定义。Slice<Person>LIMIT+1ResultSetExtractor
4 运行分页查询,返回 。仅选择给定页面边界内的数据,并可能选择计数查询以确定总计数。 不支持自定义。Page<Person>ResultSetExtractor
5 查找给定条件的单个实体。 它以非唯一结果完成。IncorrectResultSizeDataAccessException
6 与 <3> 相比,即使查询生成更多结果文档,也始终发出第一个实体。
7 该方法显示对具有给定 .findByLastnamelastname
8 该方法返回一个 ,这使得值在从数据库返回后立即成为可能。streamByLastnameStream
9 您可以使用 Spring Expression Language 动态解析参数。 在此示例中,Spring Security 用于解析当前用户的用户名。

下表显示了查询方法支持的关键字:Spring中文文档

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

AfterSpring中文文档

findByBirthdateAfter(Date date)Spring中文文档

birthdate > dateSpring中文文档

GreaterThanSpring中文文档

findByAgeGreaterThan(int age)Spring中文文档

age > ageSpring中文文档

GreaterThanEqualSpring中文文档

findByAgeGreaterThanEqual(int age)Spring中文文档

age >= ageSpring中文文档

BeforeSpring中文文档

findByBirthdateBefore(Date date)Spring中文文档

birthdate < dateSpring中文文档

LessThanSpring中文文档

findByAgeLessThan(int age)Spring中文文档

age < ageSpring中文文档

LessThanEqualSpring中文文档

findByAgeLessThanEqual(int age)Spring中文文档

age <= ageSpring中文文档

BetweenSpring中文文档

findByAgeBetween(int from, int to)Spring中文文档

age BETWEEN from AND toSpring中文文档

NotBetweenSpring中文文档

findByAgeNotBetween(int from, int to)Spring中文文档

age NOT BETWEEN from AND toSpring中文文档

InSpring中文文档

findByAgeIn(Collection<Integer> ages)Spring中文文档

age IN (age1, age2, ageN)Spring中文文档

NotInSpring中文文档

findByAgeNotIn(Collection ages)Spring中文文档

age NOT IN (age1, age2, ageN)Spring中文文档

IsNotNull,NotNullSpring中文文档

findByFirstnameNotNull()Spring中文文档

firstname IS NOT NULLSpring中文文档

IsNull,NullSpring中文文档

findByFirstnameNull()Spring中文文档

firstname IS NULLSpring中文文档

Like, ,StartingWithEndingWithSpring中文文档

findByFirstnameLike(String name)Spring中文文档

firstname LIKE nameSpring中文文档

NotLike,IsNotLikeSpring中文文档

findByFirstnameNotLike(String name)Spring中文文档

firstname NOT LIKE nameSpring中文文档

Containing在字符串上Spring中文文档

findByFirstnameContaining(String name)Spring中文文档

firstname LIKE '%' + name + '%'Spring中文文档

NotContaining在字符串上Spring中文文档

findByFirstnameNotContaining(String name)Spring中文文档

firstname NOT LIKE '%' + name + '%'Spring中文文档

(No keyword)Spring中文文档

findByFirstname(String name)Spring中文文档

firstname = nameSpring中文文档

NotSpring中文文档

findByFirstnameNot(String name)Spring中文文档

firstname != nameSpring中文文档

IsTrue,TrueSpring中文文档

findByActiveIsTrue()Spring中文文档

active IS TRUESpring中文文档

IsFalse,FalseSpring中文文档

findByActiveIsFalse()Spring中文文档

active IS FALSESpring中文文档

查询派生仅限于可以在子句中使用而不使用联接的属性。WHERE
1 该方法显示对具有给定 . 通过分析可与 和 连接的约束的方法名称来派生查询。 因此,方法名称将生成 .firstnameAndOrSELECT … FROM person WHERE firstname = :firstname
2 用于将偏移量和排序参数传递到数据库。Pageable
3 返回 .选择行以确定是否有更多数据可供使用。 不支持自定义。Slice<Person>LIMIT+1ResultSetExtractor
4 运行分页查询,返回 。仅选择给定页面边界内的数据,并可能选择计数查询以确定总计数。 不支持自定义。Page<Person>ResultSetExtractor
5 查找给定条件的单个实体。 它以非唯一结果完成。IncorrectResultSizeDataAccessException
6 与 <3> 相比,即使查询生成更多结果文档,也始终发出第一个实体。
7 该方法显示对具有给定 .findByLastnamelastname
8 该方法返回一个 ,这使得值在从数据库返回后立即成为可能。streamByLastnameStream
9 您可以使用 Spring Expression Language 动态解析参数。 在此示例中,Spring Security 用于解析当前用户的用户名。
表 1.查询方法支持的关键字
关键词 样本 合乎逻辑的结果

AfterSpring中文文档

findByBirthdateAfter(Date date)Spring中文文档

birthdate > dateSpring中文文档

GreaterThanSpring中文文档

findByAgeGreaterThan(int age)Spring中文文档

age > ageSpring中文文档

GreaterThanEqualSpring中文文档

findByAgeGreaterThanEqual(int age)Spring中文文档

age >= ageSpring中文文档

BeforeSpring中文文档

findByBirthdateBefore(Date date)Spring中文文档

birthdate < dateSpring中文文档

LessThanSpring中文文档

findByAgeLessThan(int age)Spring中文文档

age < ageSpring中文文档

LessThanEqualSpring中文文档

findByAgeLessThanEqual(int age)Spring中文文档

age <= ageSpring中文文档

BetweenSpring中文文档

findByAgeBetween(int from, int to)Spring中文文档

age BETWEEN from AND toSpring中文文档

NotBetweenSpring中文文档

findByAgeNotBetween(int from, int to)Spring中文文档

age NOT BETWEEN from AND toSpring中文文档

InSpring中文文档

findByAgeIn(Collection<Integer> ages)Spring中文文档

age IN (age1, age2, ageN)Spring中文文档

NotInSpring中文文档

findByAgeNotIn(Collection ages)Spring中文文档

age NOT IN (age1, age2, ageN)Spring中文文档

IsNotNull,NotNullSpring中文文档

findByFirstnameNotNull()Spring中文文档

firstname IS NOT NULLSpring中文文档

IsNull,NullSpring中文文档

findByFirstnameNull()Spring中文文档

firstname IS NULLSpring中文文档

Like, ,StartingWithEndingWithSpring中文文档

findByFirstnameLike(String name)Spring中文文档

firstname LIKE nameSpring中文文档

NotLike,IsNotLikeSpring中文文档

findByFirstnameNotLike(String name)Spring中文文档

firstname NOT LIKE nameSpring中文文档

Containing在字符串上Spring中文文档

findByFirstnameContaining(String name)Spring中文文档

firstname LIKE '%' + name + '%'Spring中文文档

NotContaining在字符串上Spring中文文档

findByFirstnameNotContaining(String name)Spring中文文档

firstname NOT LIKE '%' + name + '%'Spring中文文档

(No keyword)Spring中文文档

findByFirstname(String name)Spring中文文档

firstname = nameSpring中文文档

NotSpring中文文档

findByFirstnameNot(String name)Spring中文文档

firstname != nameSpring中文文档

IsTrue,TrueSpring中文文档

findByActiveIsTrue()Spring中文文档

active IS TRUESpring中文文档

IsFalse,FalseSpring中文文档

findByActiveIsFalse()Spring中文文档

active IS FALSESpring中文文档

查询派生仅限于可以在子句中使用而不使用联接的属性。WHERE

查询查找策略

JDBC 模块支持手动将查询定义为注释中的 String 或属性文件中的命名查询。@QuerySpring中文文档

从方法的名称派生查询目前仅限于简单属性,这意味着属性直接存在于聚合根中。 此外,此方法仅支持选择查询。Spring中文文档

@Query

下面的示例演示如何使用声明查询方法:@QuerySpring中文文档

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

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

为了将查询结果转换为实体,默认情况下使用与 Spring Data JDBC 自身生成的查询相同的方法。 您提供的查询必须与预期的格式匹配。 必须提供实体构造函数中使用的所有属性的列。 通过 setter、wither 或字段访问设置的属性的列是可选的。 不会设置结果中没有匹配列的属性。 该查询用于填充聚合根、嵌入实体和一对一关系,包括作为 SQL 数组类型存储和加载的基元类型的数组。 为实体的地图、列表、集合和数组生成单独的查询。RowMapperRowMapperSpring中文文档

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

查询可能包含允许绑定变量的 SpEL 表达式。 这样的 SpEL 表达式将被替换为 bind 变量,并且该变量将绑定到 SpEL 表达式的结果。Spring中文文档

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

这可用于访问参数的成员,如上面的示例所示。 对于更复杂的用例,可以在应用程序上下文中提供,这反过来又可以使任何对象在 SpEL 中可用。EvaluationContextExtensionSpring中文文档

Spring 完全支持 Java 8 基于编译器标志的参数名称发现。 通过在生成中使用此标志作为调试信息的替代方法,可以省略命名参数的批注。-parameters@Param
Spring Data JDBC 仅支持命名参数。
请注意,基于字符串的查询不支持分页,也不接受 、 ,并且作为查询参数,对于这些查询,需要重写查询。 如果要应用限制,请使用 SQL 表达此意图,并自行将相应的参数绑定到查询。SortPageRequestLimit
Spring 完全支持 Java 8 基于编译器标志的参数名称发现。 通过在生成中使用此标志作为调试信息的替代方法,可以省略命名参数的批注。-parameters@Param
Spring Data JDBC 仅支持命名参数。

命名查询

如果注释中没有给出查询,如上一节所述,Spring Data JDBC 将尝试查找命名查询。 有两种方法可以确定查询的名称。 默认设置是采用查询的域类,即存储库的聚合根目录,采用其简单名称,并附加用 分隔的方法名称。 或者,批注具有一个属性,该属性可用于指定要查找的查询的名称。.@QuerynameSpring中文文档

命名查询应在类路径上的属性文件中提供。META-INF/jdbc-named-queries.propertiesSpring中文文档

可以通过将值设置为 来更改该文件的位置。@EnableJdbcRepositories.namedQueriesLocationSpring中文文档

命名查询的处理方式与批注提供的查询相同。Spring中文文档

自定义查询方法

流式处理结果

当您将 Stream 指定为查询方法的返回类型时,Spring Data JDBC 会在元素可用时立即返回它们。 在处理大量数据时,这适用于减少延迟和内存要求。Spring中文文档

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

自定义或RowMapperResultSetExtractor

注释允许您指定自定义或使用。 属性,并允许您指定要使用的类,这些类将使用默认构造函数进行实例化。 或者,您可以从 Spring 应用程序上下文中设置 或 Bean 名称。@QueryRowMapperResultSetExtractorrowMapperClassresultSetExtractorClassrowMapperClassRefresultSetExtractorClassRefSpring中文文档

如果不仅要对单个方法使用某个方法,而且要对具有返回特定类型的自定义查询的所有方法使用特定方法, 您可以注册一个 Bean 并注册一个 Per Method 返回类型。 以下示例演示如何注册:RowMapperRowMapperMapRowMapperDefaultQueryMappingConfigurationSpring中文文档

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

在确定方法使用哪个方法时,根据方法的返回类型,将遵循以下步骤:RowMapperSpring中文文档

  1. 如果类型是简单类型,则使用 no。RowMapperSpring中文文档

    相反,查询应返回具有单个列的单行,并将返回类型的转换应用于该值。Spring中文文档

  2. 将迭代 中的实体类,直到找到一个是相关返回类型的超类或接口。 使用该类的注册。QueryMappingConfigurationRowMapperSpring中文文档

    迭代按注册顺序进行,因此请确保在特定类型之后注册更通用的类型。Spring中文文档

如果适用,包装类型(如集合或已解包)。 因此,返回类型 使用前面进程中的类型。OptionalOptional<Person>PersonSpring中文文档

使用自定义 、 或自定义会禁用实体回调和生命周期事件,因为结果映射可以根据需要发出自己的事件/回调。RowMapperQueryMappingConfiguration@Query(rowMapperClass=…)ResultSetExtractor

修改查询

可以使用 on 查询方法将查询标记为修改查询,如以下示例所示:@ModifyingSpring中文文档

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

您可以指定以下返回类型:Spring中文文档

修改查询是直接针对数据库执行的。 不会调用任何事件或回调。 因此,如果具有审核批注的字段未在批注查询中更新,则这些字段也不会更新。Spring中文文档

使用自定义 、 或自定义会禁用实体回调和生命周期事件,因为结果映射可以根据需要发出自己的事件/回调。RowMapperQueryMappingConfiguration@Query(rowMapperClass=…)ResultSetExtractor