| 
         对于最新的稳定版本,请使用 Spring Data Relational 3.4.0!  | 
    
查询方法
本节提供了有关 Spring Data JDBC 的实现和使用的一些具体信息。
您通常在存储库上触发的大多数数据访问作都会导致对数据库运行查询。 定义此类查询就是在存储库接口上声明方法,如下例所示:
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.
查询是通过解析可与And和Or.
因此,方法名称会生成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 解析当前用户的用户名。 | 
下表显示了查询方法支持的关键字:
| 关键词 | 样本 | 逻辑结果 | 
|---|---|---|
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
  | 
查询派生仅限于可在WHERE子句。 | 
用@Query
以下示例演示如何使用@Query要声明 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 的实体生成单独的查询。
属性一对一关系必须具有以关系名称加 为前缀的 name 。
例如,如果_User在上面的示例中,有一个address与属性city该列city必须贴标签address_city.
请注意,基于字符串的查询不支持分页,也不接受Sort,PageRequest和Limit作为查询参数,对于这些查询,需要重写查询。
如果要应用限制,请使用 SQL 表达此意图,并自行将相应的参数绑定到查询。 | 
查询可能包含允许绑定变量的 SPEL 表达式。 这样的 SPEL 表达式将被绑定变量替换,并且该变量将绑定到 SPEL 表达式的结果。
@Query("SELECT * FROM person WHERE id = :#{#person.id}")
Person findWithSpEL(PersonRef person);
这可用于访问参数的成员,如上面的示例所示。
有关更多涉及的使用案例,请参阅EvaluationContextExtension可以在应用程序上下文中可用,而应用程序上下文又可以使任何对象对 SPEL 可用。
Spring 完全支持 Java 8 的参数名称发现,基于-parameterscompiler 标志。
通过在构建中使用此标志作为调试信息的替代方法,您可以省略@Param注解。 | 
| Spring Data JDBC 仅支持命名参数。 | 
命名查询
如果 Comments 中没有给出查询,如上一节所述,Spring Data JDBC 将尝试查找命名查询。
有两种方法可以确定查询的名称。
默认情况下,采用查询的 domain 类,即存储库的聚合根,采用其简单名称,并附加由分隔..
或者,@Queryannotation 具有name属性,该属性可用于指定要查找的查询的名称。
命名查询应在属性文件中提供META-INF/jdbc-named-queries.properties在 Classpath 上。
可以通过将值设置为@EnableJdbcRepositories.namedQueriesLocation.
命名查询的处理方式与 annotation 提供的查询相同。
流式处理结果
当您指定 Stream 作为查询方法的返回类型时, Spring Data JDBC 会在元素可用后立即返回这些元素。 在处理大量数据时,这适用于减少延迟和内存需求。
流包含与数据库的开放连接。
为避免内存泄漏,最终需要通过关闭流来关闭该连接。
推荐的方法是try-with-resource clause.
这也意味着,一旦关闭了与数据库的连接,流就无法获取更多元素,并可能引发异常。
习惯RowMapper或ResultSetExtractor
这@Queryannotation 允许您指定自定义RowMapper或ResultSetExtractor使用。
属性rowMapperClass和resultSetExtractorClass允许您指定要使用的类,这些类将使用默认构造函数进行实例化。
或者,您可以将rowMapperClassRef或resultSetExtractorClassRef添加到 Spring 应用程序上下文中的 bean 名称。
如果您想使用某个RowMapper不仅适用于单个方法,还适用于自定义查询返回特定类型的所有方法,
您可以注册一个RowMapperMapbean 并注册一个RowMapperper 方法返回类型。
以下示例演示如何注册DefaultQueryMappingConfiguration:
@Bean
QueryMappingConfiguration rowMappers() {
  return new DefaultQueryMappingConfiguration()
    .register(Person.class, new PersonRowMapper())
    .register(Address.class, new AddressRowMapper());
}
确定哪个RowMapper要使用 for 方法,请根据方法的返回类型执行以下步骤:
- 
如果类型是简单类型,则没有
RowMapper被使用。相反,查询应返回具有单个列的单个行,并且对该值应用到返回类型的转换。
 - 
的
QueryMappingConfiguration进行迭代,直到找到一个是相关返回类型的超类或接口。 这RowMapperregistered for that class 的 。迭代按照注册的顺序进行,因此请确保在特定类型之后注册更通用的类型。
 
如果适用,包装器类型(如 collections 或Optional解包。
因此,返回类型Optional<Person>使用Persontype 在前面的进程中。
使用自定义RowMapper通过QueryMappingConfiguration,@Query(rowMapperClass=…)或自定义ResultSetExtractor禁用 Entity Callbacks 和 Lifecycle Events,因为结果映射可以根据需要发出自己的事件/回调。 |