Spring Data(数据)R2DBC

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Data(数据)R2DBC相关的知识,希望对你有一定的参考价值。

版本 3.0.0

Spring Data R2DBC项目将Spring的核心概念应用于开发使用关系数据库R2DBC​驱动程序的解决方案。 我们提供了用于存储和查询行的高级抽象。​​DatabaseClient​

本文档是 Spring Data - R2DBC 支持的参考指南。 它解释了R2DBC模块的概念和语义。

本节提供了一些关于 Spring 和数据库的基本介绍。

Spring

1. 学习之春

Spring Data 使用 Spring 框架的核心功能,包括:

  • 国际奥委会容器
  • 型式转换系统
  • 表达式语言
  • JMX 集成
  • DAO 异常层次结构。

虽然你不需要知道Spring API,但理解它们背后的概念是很重要的。 至少,控制反转 (IoC) 背后的想法应该很熟悉,并且您应该熟悉您选择使用的任何 IoC 容器。

您可以直接使用 R2DBC 支持的核心功能,而无需调用 Spring 容器的 IoC 服务。 这很像,它可以“独立”使用,而无需 Spring 容器的任何其他服务。 要使用 Spring Data R2DBC 的所有功能,例如存储库支持,您需要将库的某些部分配置为使用 Spring。​​JdbcTemplate​

要了解有关 Spring 的更多信息,请参阅详细解释 Spring 框架的综合文档。 有很多关于这个主题的文章、博客条目和书籍。 有关更多信息,请参阅 Spring 框架主页。

2. 什么是R2DBC?

R2DBC是反应式关系数据库连接的首字母缩写。 R2DBC 是一项 API 规范计划,它声明了一个响应式 API,由驱动程序供应商实现以访问其关系数据库。

关于创建R2DBC的部分答案是需要一个非阻塞应用程序堆栈来处理少量线程的并发性,并以更少的硬件资源进行扩展。 重用标准化的关系数据库访问 API(即 JDBC)无法满足这种需求,因为 JDBC 是一个完全阻塞的 API。 尝试使用有限的使用来补偿阻止行为。​​ThreadPool​

答案的另一部分是大多数应用程序使用关系数据库来存储其数据。 虽然一些NoSQL数据库供应商为其数据库提供了反应式数据库客户端,但对于大多数项目来说,迁移到NoSQL不是一个选项。 这就是新的通用 API 作为任何非阻塞数据库驱动程序的基础的动机。 虽然开源生态系统托管各种非阻塞关系数据库驱动程序实现,但每个客户端都带有特定于供应商的 API,因此不可能在这些库之上建立通用层。

3. 什么是反应式?

术语“反应式”是指围绕对更改、可用性和可处理性做出反应而构建的编程模型 - 网络组件对 I/O 事件做出反应,UI 控制器对鼠标事件做出反应,可用的资源等。 从这个意义上说,非阻塞是被动的,因为我们现在不是被阻止,而是在操作完成或数据可用时对通知做出反应。

我们弹簧团队还有另一个重要的机制与反应性有关,那就是非阻塞背压。 在同步的命令性代码中,阻止调用是一种自然形式的背压,迫使调用方等待。 在非阻塞代码中,控制事件速率变得至关重要,这样快速生产者就不会淹没其目标。

Reactive Streams 是一个小规范(在Java 9 中也采用),它定义了异步组件与背压之间的交互。 例如,数据存储库(充当发布服务器)可以生成数据,然后 HTTP 服务器(充当订阅服务器)可以将其写入响应。 反应式流的主要目的是让订阅者控制发布者生成数据的速度或速度。

4. 反应式接口

反应式流在互操作性方面起着重要作用。它对库和基础结构组件感兴趣,但作为应用程序 API 不太有用,因为它太低级了。 应用程序需要一个更高层次、更丰富的功能性 API 来组成异步逻辑 - 类似于 Java 8 Stream API,但不仅适用于表。 这就是响应式库所扮演的角色。

Project Reactor是 Spring Data R2DBC 的首选反应式库。 它提供了单声道和通量API 类型,通过一组与运算符的 ReactiveX 词汇表一致的丰富运算符来处理 () 和 () 的数据序列。 反应器是一个反应流库,因此,它的所有运算符都支持非阻塞背压。 Reactor 非常关注服务器端 Java。它是与Spring密切合作开发的。​​0..1​​​​Mono​​​​0..N​​​​Flux​

Spring Data R2DBC 需要 Project Reactor 作为核心依赖项,但它可以通过 Reactive Streams 规范与其他响应式库互操作。 作为一般规则,Spring Data R2DBC 存储库接受普通输入,在内部将其适应 Reactor 类型,使用该类型,并返回 aor aas 输出。 因此,您可以传递 anyas 输入并对输出应用操作,但您需要调整输出以用于另一个反应式库。 只要可行,Spring Data就会透明地适应RxJava或其他反应式库的使用。​​Publisher​​​​Mono​​​​Flux​​​​Publisher​

5. 要求

Spring Data R2DBC 3.x二进制文件需要:

  • JDK 17 级及以上
  • Spring 框架6.0.0 及更高版本
  • R2DBC及以上

6. 其他帮助资源

学习一个新框架并不总是那么简单。 在本节中,我们尝试提供我们认为易于遵循的指南,以便从Spring Data R2DBC模块开始。 但是,如果您遇到问题或需要建议,请使用以下链接之一:

社区论坛

Stack Overflow上的Spring Data是所有Spring Data(不仅仅是R2DBC)用户共享信息和互相帮助的标签。 请注意,只有发布时才需要注册。

专业支持

专业的,从源头支持,保证响应时间,可从Spring Data和Spring背后的公司Pivotal Software,Inc.获得。

7. 后续开发

  • 有关 Spring Data R2DBC 源代码存储库、夜间构建和快照工件的信息,请参阅 Spring Data R2DBC主页。
  • 您可以通过Stack Overflow上的社区与开发人员进行交互,从而帮助Spring Data最好地满足Spring社区的需求。
  • 如果您遇到错误或想要提出改进建议,请在Spring Data R2DBC问题跟踪器上创建一个票证。
  • 要及时了解 Spring 生态系统中的最新消息和公告,请订阅 Spring 社区门户。
  • 您也可以在Twitter(SpringData)上关注Spring博客或Spring Data项目团队。

8. 项目元数据

  • 版本控制:https://github.com/spring-projects/spring-data-r2dbc
  • 错误跟踪器:https://github.com/spring-projects/spring-data-r2dbc/issues
  • 发布库:https://repo.spring.io/libs-release
  • 里程碑存储库:https://repo.spring.io/libs-milestone
  • 快照存储库:https://repo.spring.io/libs-snapshot

9. 升级弹簧数据

有关如何从早期版本的 Spring 数据升级的说明在项目wiki 上提供。 按照发行说明部分中的链接查找要升级到的版本。

升级说明始终是发行说明中的第一项。如果您落后多个版本,请确保您还查看了您跳转的版本的发行说明。

10. 依赖关系

由于各个 Spring 数据模块的开始日期不同,因此它们中的大多数都带有不同的主要和次要版本号。找到兼容版本的最简单方法是依靠我们随附的与定义的兼容版本一起提供的春季数据发布列车 BOM。在 Maven 项目中,您将在 POM 的部分中声明此依赖项,如下所示:​​<dependencyManagement />​

例 1.使用弹簧数据发布列车物料清单

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-bom</artifactId>
<version>2022.0.0</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>

当前发布训练版本是。火车版本使用带有图案的犊牛。 对于 GA 版本和服务版本,版本名称如下,对于所有其他版本,版本名称如下:,其中可以是以下之一:​​2022.0.0​​​​YYYY.MINOR.MICRO​​​​$calver​​​​$calver-$modifier​​​​modifier​

  • ​SNAPSHOT​​:当前快照
  • ​M1​​,,等等:里程碑M2
  • ​RC1​​,,等等:发布候选版本RC2

您可以在我们的Spring 数据示例存储库中找到使用 BOM 的工作示例。有了这个,你可以声明你想要使用的 Spring 数据模块,而无需在块中有一个版本,如下所示:​​<dependencies />​

例 2.声明对 Spring 数据模块的依赖关系

<dependencies>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
</dependency>
<dependencies>

10.1. 使用 Spring 引导进行依赖管理

Spring Boot 会为你选择最新版本的 Spring 数据模块。如果仍要升级到较新版本,请将 要使用的训练版本和迭代的属性。​​spring-data-releasetrain.version​

10.2. 弹簧框架

Spring 数据模块的当前版本需要 Spring Framework 6.0.0 或更高版本。这些模块还可以使用该次要版本的较旧错误修复版本。但是,强烈建议使用该代中的最新版本。

11. 使用 Spring 数据存储库

Spring 数据存储库抽象的目标是显著减少为各种持久性存储实现数据访问层所需的样板代码量。


Spring 数据存储库文档和您的模块



本章解释了 Spring 数据存储库的核心概念和接口。 本章中的信息来自 Spring 数据共享模块。 它使用 Jakarta 持久性 API (JPA) 模块的配置和代码示例。 “存储库查询关键字”涵盖了存储库抽象通常支持的查询方法关键字。 有关模块特定功能的详细信息,请参阅本文档有关该模块的章节。


11.1. 核心概念

Spring 数据存储库抽象中的中心接口是。 它采用要管理的域类以及域类的 ID 类型作为类型参数。 此接口主要充当标记接口,用于捕获要使用的类型,并帮助您发现扩展此接口的接口。 CrudRepository 和ListCrudRepository接口为正在管理的实体类提供了复杂的 CRUD 功能。​​Repository​

示例 3.界面​​CrudRepository​

public interface CrudRepository<T, ID> extends Repository<T, ID> 

<S extends T> S save(S entity);

Optional<T> findById(ID primaryKey);

Iterable<T> findAll();

long count();

void delete(T entity);

boolean existsById(ID primaryKey);

// … more functionality omitted.

保存给定的实体。

返回由给定 ID 标识的实体。

返回所有实体。

返回实体数。

删除给定实体。

指示具有给定 ID 的实体是否存在。

​ListCrudRepository​​提供等效的方法,但它们返回方法返回 an。​​List​​​​CrudRepository​​​​Iterable​

我们还提供特定于持久性技术的抽象,例如 asor。 这些接口扩展并公开了底层持久性技术的功能,以及相当通用的持久性技术无关的接口,例如。​​JpaRepository​​​​MongoRepository​​​​CrudRepository​​​​CrudRepository​

除此之外,还有一个PagingAndSortingRepository抽象,它添加了其他方法来简化对实体的分页访问:​​CrudRepository​

例 4.接口​​PagingAndSortingRepository​

public interface PagingAndSortingRepository<T, ID>  

Iterable<T> findAll(Sort sort);

Page<T> findAll(Pageable pageable);

要访问页面大小为 20 的第二页,您可以执行以下操作:​​User​

PagingAndSortingRepository<User, Long> repository = // … get access to a bean
Page<User> users = repository.findAll(PageRequest.of(1, 20));

除了查询方法之外,还可以对计数查询和删除查询进行查询派生。 以下列表显示了派生计数查询的接口定义:

例 5.派生计数查询

interface UserRepository extends CrudRepository<User, Long> 

long countByLastname(String lastname);

以下清单显示了派生删除查询的接口定义:

例 6.派生删除查询

interface UserRepository extends CrudRepository<User, Long> 

long deleteByLastname(String lastname);

List<User> removeByLastname(String lastname);

11.2. 查询方法

标准 CRUD 功能存储库通常对基础数据存储具有查询。 使用 Spring Data,声明这些查询变成了一个四步过程:

  1. 声明扩展存储库或其子接口之一的接口,并将其键入应处理的域类和 ID 类型,如以下示例所示:


interface PersonRepository extends Repository<Person, Long>  … 
  1. 在接口上声明查询方法。


interface PersonRepository extends Repository<Person, Long> 
List<Person> findByLastname(String lastname);
  1. 设置 Spring 以使用JavaConfig或XML 配置为这些接口创建代理实例。

    爪哇岛
@EnableJpaRepositories
class Config …

+ 请注意,JavaConfig 变体不会显式配置包,因为缺省情况下使用带注释的类的包。 要自定义要扫描的包,请使用特定于数据存储的存储库注释的属性之一。basePackage…@EnableJpaRepositories

  1. 注入存储库实例并使用它,如以下示例所示:
class SomeClient 

private final PersonRepository repository;

SomeClient(PersonRepository repository)
this.repository = repository;


void doSomething()
List<Person> persons = repository.findByLastname("Matthews");

以下各节详细介绍了每个步骤:

  • 定义存储库接口
  • 定义查询方法
  • 创建存储库实例
  • Spring 数据存储库的自定义实现

11.3. 定义存储库接口

要定义存储库接口,首先需要定义特定于域类的存储库接口。 接口必须扩展并键入域类和 ID 类型。 如果要公开该域类型的 CRUD 方法,可以扩展或其变体之一,而不是。​​Repository​​​​CrudRepository​​​​Repository​

11.3.1. 微调存储库定义

您可以通过几种变体开始使用存储库界面。

典型的方法是扩展,这为您提供了 CRUD 功能的方法。 CRUD 代表 创建、读取、更新、删除。 在 3.0 版中,我们还引入了这与 但是对于那些返回多个实体的方法,它返回的是您可能发现更容易使用的方法。​​CrudRepository​​​​ListCrudRepository​​​​CrudRepository​​​​List​​​​Iterable​

如果您使用的是反应式存储,则可以选择,或者取决于您使用的反应式框架。​​ReactiveCrudRepository​​​​RxJava3CrudRepository​

如果你正在使用 Kotlin,你可以选择哪个利用 Kotlin 的协程。​​CoroutineCrudRepository​

此外,您还可以扩展,,,或者如果您需要允许指定抽象或在第一种情况下指定抽象的方法。 请注意,各种排序存储库不再像在 Spring 数据版本 3.0 之前那样扩展其各自的 CRUD 存储库。 因此,如果需要这两个接口的功能,则需要扩展这两个接口。​​PagingAndSortingRepository​​​​ReactiveSortingRepository​​​​RxJava3SortingRepository​​​​CoroutineSortingRepository​​​​Sort​​​​Pageable​

如果您不想扩展 Spring 数据接口,您还可以使用注释存储库接口。 扩展其中一个 CRUD 存储库接口会公开一组完整的方法来操作实体。 如果您希望对要公开的方法有选择性,请将要公开的方法从 CRUD 存储库复制到域存储库中。 执行此操作时,可以更改方法的返回类型。 如果可能,Spring 数据将遵循返回类型。 例如,对于返回多个实体的方法,您可以选择 VAVR 列表。​​@RepositoryDefinition​​​​Iterable<T>​​​​List<T>​​​​Collection<T>​

如果应用程序中的许多存储库应具有相同的方法集,则可以定义自己的基本接口进行继承。 必须对这样的接口进行注释。 这可以防止 Spring Data 尝试直接创建它的实例并失败,因为它无法确定该存储库的实体,因为它仍然包含一个通用类型变量。​​@NoRepositoryBean​

下面的示例演示如何有选择地公开 CRUD 方法(在本例中为):​​findById​​​​save​

例 7.有选择地公开 CRUD 方法

@NoRepositoryBean
interface MyBaseRepository<T, ID> extends Repository<T, ID>

Optional<T> findById(ID id);

<S extends T> S save(S entity);


interface UserRepository extends MyBaseRepository<User, Long>
User findByEmailAddress(EmailAddress emailAddress);

在前面的示例中,您为所有域存储库和公开以及定义了通用基本接口。这些方法被路由到 Spring Data 提供的您选择的存储的基本存储库实现中(例如,如果您使用 JPA,则实现是),因为它们与方法签名匹配。 因此,现在可以保存用户,按ID查找单个用户,并触发查询以按电子邮件地址查找。​​findById(…)​​​​save(…)​​​​SimpleJpaRepository​​​​CrudRepository​​​​UserRepository​​​​Users​

中间存储库接口带有注释。 确保将该注释添加到 Spring Data 在运行时不应为其创建实例的所有存储库接口。​​@NoRepositoryBean​

11.3.2. 使用具有多个 Spring 数据模块的存储库

在应用程序中使用唯一的 Spring 数据模块使事情变得简单,因为定义范围内的所有存储库接口都绑定到 Spring 数据模块。 有时,应用程序需要使用多个 Spring 数据模块。 在这种情况下,存储库定义必须区分持久性技术。 当它在类路径上检测到多个存储库工厂时,Spring Data 进入严格的存储库配置模式。 严格配置使用存储库或域类的详细信息来决定存储库定义的 Spring 数据模块绑定:

  1. 如果存储库定义扩展了特定于模块的存储库,则它是特定 Spring 数据模块的有效候选者。
  2. 如果域类使用特定于模块的类型注释进行注释,则它是特定 Spring 数据模块的有效候选者。 Spring Data 模块接受第三方注释(例如 JPA)或提供自己的注释(例如 Spring Data MongoDB 和 Spring Data Elasticsearch)。@Entity@Document

以下示例显示了使用特定于模块的接口(在本例中为 JPA)的存储库:

例 8.使用特定于模块的接口的存储库定义

interface MyRepository extends JpaRepository<User, Long>  

@NoRepositoryBean
interface MyBaseRepository<T, ID> extends JpaRepository<T, ID> …

interface UserRepository extends MyBaseRepository<User, Long> …

​MyRepository​​并扩展其类型层次结构。 它们是 Spring Data JPA 模块的有效候选者。​​UserRepository​​​​JpaRepository​

以下示例显示了使用通用接口的存储库:

例 9.使用通用接口的存储库定义

interface AmbiguousRepository extends Repository<User, Long>  … 

@NoRepositoryBean
interface MyBaseRepository<T, ID> extends CrudRepository<T, ID> …

interface AmbiguousUserRepository extends MyBaseRepository<User, Long> …

​AmbiguousRepository​​并仅在其类型层次结构中扩展。 虽然这在使用唯一的 Spring 数据模块时很好,但多个模块无法区分这些存储库应该绑定到哪个特定的 Spring 数据。​​AmbiguousUserRepository​​​​Repository​​​​CrudRepository​

以下示例显示了一个使用带有注释的域类的存储库:

例 10.使用带有注释的域类的存储库定义

interface PersonRepository extends Repository<Person, Long>  … 

@Entity
class Person …

interface UserRepository extends Repository<User, Long> …

@Document
class User …

​PersonRepository​​引用,它用JPAannotation注释,所以这个存储库显然属于Spring Data JPA.references,它用Spring Data MongoDB的sannotation注释。​​Person​​​​@Entity​​​​UserRepository​​​​User​​​​@Document​

以下错误示例显示了一个使用具有混合注释的域类的存储库:

例 11.使用具有混合注释的域类的存储库定义

interface JpaPersonRepository extends Repository<Person, Long>  … 

interface MongoDBPersonRepository extends Repository<Person, Long> …

@Entity
@Document
class Person …

这个例子展示了一个同时使用JPA和Spring Data MongoDB注释的域类。 它定义了两个存储库,并且。 一个用于JPA,另一个用于MongoDB使用。 Spring 数据不再能够区分存储库,这会导致未定义的行为。​​JpaPersonRepository​​​​MongoDBPersonRepository​

存储库类型详细信息和区分域类注释用于严格的存储库配置,以识别特定 Spring 数据模块的存储库候选者。 可以对同一域类型使用多个特定于持久性技术的注释,并允许跨多个持久性技术重用域类型。 但是,Spring Data 无法再确定绑定存储库的唯一模块。

区分存储库的最后一种方法是确定存储库基础包的范围。 基本包定义扫描存储库接口定义的起点,这意味着存储库定义位于相应的包中。 默认情况下,注释驱动的配置使用配置类的包。 基于 XML 的配置中的基本包是必需的。

以下示例显示了基本包的注释驱动配置:

例 12.注释驱动的基本包配置

@EnableJpaRepositories(basePackages = "com.acme.repositories.jpa")
@EnableMongoRepositories(basePackages = "com.acme.repositories.mongo")
class Configuration …

11.4. 定义查询方法

存储库代理有两种方法可以从方法名称派生特定于存储的查询:

  • 通过直接从方法名称派生查询。
  • 通过使用手动定义的查询。

可用选项取决于实际商店。 但是,必须有一个策略来决定创建什么实际查询。 下一节介绍可用选项。

11.4.1. 查询查找策略

存储库基础结构可以使用以下策略来解析查询。 对于 Java 配置,您可以使用注释的属性。 特定数据存储可能不支持某些策略。​​queryLookupStrategy​​​​EnableJpaRepositories​

  • ​CREATE​​尝试从查询方法名称构造特定于存储的查询。 一般方法是从方法名称中删除一组给定的已知前缀,并分析方法的其余部分。 您可以在“查询创建”中阅读有关查询构造的更多信息。
  • ​USE_DECLARED_QUERY​​尝试查找已声明的查询,如果找不到查询,则会引发异常。 查询可以通过某处的注释定义,也可以通过其他方式声明。 请参阅特定商店的文档以查找该商店的可用选项。 如果存储库基础结构在引导时找不到该方法的声明查询,则会失败。
  • ​CREATE_IF_NOT_FOUND​​(默认值)组合沙。 它首先查找已声明的查询,如果未找到已声明的查询,则会创建一个基于名称的自定义方法查询。 这是默认的查找策略,因此,如果未显式配置任何内容,则使用此方法。 它允许按方法名称快速定义查询,但也允许根据需要引入声明的查询来自定义调整这些查询。CREATEUSE_DECLARED_QUERY

11.4.2. 查询创建

Spring 数据存储库基础结构中内置的查询生成器机制对于构建对存储库实体的约束查询非常有用。

下面的示例演示如何创建多个查询:

例 13.从方法名称创建查询

interface PersonRepository extends Repository<Person, Long> 

List<Person> findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname);

// Enables the distinct flag for the query
List<Person> findDistinctPeopleByLastnameOrFirstname(String lastname, String firstname);
List<Person> findPeopleDistinctByLastnameOrFirstname(String lastname, String firstname);

// Enabling ignoring case for an individual property
List<Person> findByLastnameIgnoreCase(String lastname);
// Enabling ignoring case for all suitable properties
List<Person> findByLastnameAndFirstnameAllIgnoreCase(String lastname, String firstname);

// Enabling static ORDER BY for a query
List<Person> findByLastnameOrderByFirstnameAsc(String lastname);
List<Person> findByLastnameOrderByFirstnameDesc(String lastname);

分析查询方法名称分为主语和谓语。 第一部分 (,) 定义查询的主题,第二部分构成谓词。 引言子句(主语)可以包含进一步的表达式。 (或其他引入关键字)之间的任何文本都被视为描述性的,除非使用结果限制关键字之一,例如 ato 在要创建的查询上设置不同的标志或Top/First以限制查询结果。find…Byexists…ByfindByDistinct

附录包含查询方法主题关键字和查询方法谓词关键字的完整列表,包括排序和字母大小写修饰符。 但是,第一个充当分隔符来指示实际条件谓词的开始。 在非常基本的级别上,您可以定义实体属性的条件并将它们与 and 连接起来。​​By​​​​And​​​​Or​

分析方法的实际结果取决于为其创建查询的暂留存储。 但是,有一些一般事项需要注意:

  • 表达式通常是属性遍历与可以连接的运算符相结合。 可以将属性表达式与 and 组合在一起。 您还可以获得对运算符的支持,例如,,, 和属性表达式。 支持的运算符可能因数据存储而异,因此请参阅参考文档的相应部分。ANDORBetweenLessThanGreaterThanLike
  • 方法解析器支持为单个属性(例如)或支持忽略大小写的类型的所有属性(通常是实例 — 例如,)设置 anflag。 是否支持忽略案例可能因商店而异,因此请参阅特定于商店的查询方法的参考文档中的相关部分。IgnoreCasefindByLastnameIgnoreCase(…)StringfindByLastnameAndFirstnameAllIgnoreCase(…)
  • 可以通过将 anclause 追加到引用属性的查询方法并提供排序方向 (or) 来应用静态排序。 要创建支持动态排序的查询方法,请参阅 “特殊参数处理”。OrderByAscDesc

11.4.3. 属性表达式

属性表达式只能引用托管实体的直接属性,如前面的示例所示。 在创建查询时,已确保分析的属性是托管域类的属性。 但是,也可以通过遍历嵌套属性来定义约束。 请考虑以下方法签名:

List<Person> findByAddressZipCode(ZipCode zipCode);

假设 ahas anwith a。 在这种情况下,该方法将创建属性遍历。 解析算法首先将整个部件 () 解释为属性,并检查域类中是否存在具有该名称(未大写)的属性。 如果算法成功,它将使用该属性。 如果没有,该算法将右侧驼峰案例部分的源拆分为头部和尾部,并尝试找到相应的属性 — 在我们的示例中,and。 如果算法找到具有该头部的属性,它将获取尾部并继续从那里向下构建树,以刚才描述的方式将尾部拆分。 如果第一个拆分不匹配,算法会将拆分点向左移动 (,) 并继续。​​Person​​​​Address​​​​ZipCode​​​​x.address.zipCode​​​​AddressZipCode​​​​AddressZip​​​​Code​​​​Address​​​​ZipCode​

尽管这应该适用于大多数情况,但算法可能会选择错误的属性。 假设该类也有属性。 算法将在第一轮拆分中匹配,选择错误的属性,然后失败(因为类型可能没有属性)。​​Person​​​​addressZip​​​​addressZip​​​​code​

要解决这种歧义,您可以在方法名称中使用手动定义遍历点。 所以我们的方法名称如下:​​_​

List<Person> findByAddress_ZipCode(ZipCode zipCode);

由于我们将下划线字符视为保留字符,因此强烈建议遵循标准的 Java 命名约定(即,不要在属性名称中使用下划线,而是使用驼峰大小写)。

11.4.4. 特殊参数处理

若要处理查询中的参数,请定义方法参数,如前面的示例所示。 除此之外,基础架构还可以识别某些特定类型,例如and,以动态地将分页和排序应用于您的查询。 以下示例演示了这些功能:​​Pageable​​​​Sort​

例 14。使用 、 和 in 查询方法​​Pageable​​​​Slice​​​​Sort​

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

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

List<User> findByLastname(String lastname, Sort sort);

List<User> findByLastname(String lastname, Pageable pageable);

API 获取并期望将非值传递给方法。 如果您不想应用任何排序或分页,请使用和。​​Sort​​​​Pageable​​​​null​​​​Sort.unsorted()​​​​Pageable.unpaged()​

第一种方法允许您将实例传递给查询方法,以动态地将分页添加到静态定义的查询中。 了解可用元素和页面的总数。 它通过基础结构触发计数查询来计算总数。 由于这可能很昂贵(取决于所使用的商店),因此您可以改为返回 a。 仅知道 next是否可用,这在遍历较大的结果集时可能就足够了。​​org.springframework.data.domain.Pageable​​​​Page​​​​Slice​​​​Slice​​​​Slice​

排序选项也通过实例处理。 如果只需要排序,请向方法添加参数。 如您所见,返回 ais 也是可能的。 在这种情况下,不会创建构建实际实例所需的其他元数据(这反过来意味着不会发出所需的其他计数查询)。 相反,它将查询限制为仅查找给定范围的实体。​​Pageable​​​​org.springframework.data.domain.Sort​​​​List​​​​Page​

要了解整个查询获得的页面数,您必须触发额外的计数查询。 默认情况下,此查询派生自实际触发的查询。

分页和排序

可以使用属性名称定义简单的排序表达式。 您可以连接表达式以将多个条件收集到一个表达式中。

例 15。定义排序表达式

Sort sort = Sort.by("firstname").ascending()
.and(Sort.by("lastname").descending());

有关定义排序表达式的更类型安全的方法,请从定义排序表达式的类型开始,并使用方法引用定义要排序的属性。

例 16。使用类型安全的 API 定义排序表达式

TypedSort<Person> person = Sort.sort(Person.class);

Sort sort = person.by(Person::getFirstname).ascending()
.and(person.by(Person::getLastname).descending());

​TypedSort.by(…)​​通过(通常)使用 CGlib 来使用运行时代理,这在使用 Graal VM 本机等工具时可能会干扰本机映像编译。

如果您的商店实现支持 Querydsl,您还可以使用生成的元模型类型来定义排序表达式:

例 17.使用 Querydsl API 定义排序表达式

QSort sort = QSort.by(QPerson.firstname.asc())
.and(QSort.by(QPerson.lastname.desc()));

11.4.5. 限制查询结果

可以使用 theor关键字来限制查询方法的结果,这些关键字可以互换使用。 您可以附加一个可选的数值来指定要返回的最大结果大小。 如果省略该数字,则假定结果大小为 1。 以下示例演示如何限制查询大小:​​first​​​​top​​​​top​​​​first​

例 18。限制查询的结果大小​​Top​​​​First​

User findFirstByOrderByLastnameAsc();

User findTopByOrderByAgeDesc();

Page<User> queryFirst10ByLastname(String lastname, Pageable pageable);

Slice<User> findTop3ByLastname(String lastname, Pageable pageable);

List<User> findFirst10ByLastname(String lastname, Sort sort);

List<User> findTop10ByLastname(String lastname, Pageable pageable);

限制表达式还支持支持不同查询的数据存储的关键字。 此外,对于将结果集限制为一个实例的查询,支持使用 thekeyword 将结果包装到其中。​​Distinct​​​​Optional​

如果分页或切片应用于限制查询分页(以及可用页数的计算),则会在有限的结果中应用分页或

以上是关于Spring Data(数据)R2DBC的主要内容,如果未能解决你的问题,请参考以下文章

Spring数据访问和数据访问层与业务或服务层之间的交互

Spring Data(数据)R2DBC

Spring Data R2DBC响应式操作MySQL

Spring Data R2DBC 响应式数据库操作使用

使用反应式关系数据库连接规范R2DBC操作MySQL数据库

MYSQL R2DBC 的 Spring Data 多主机设置