R2DBC 仓储

本章指出了对 R2DBC 的仓储支持的特性。这是基于在使用 Spring Data 仓储中解释的核心仓储支持。在阅读本章之前,您应该对其中解释的基本概念有充分的了解。

用法

要访问存储在关系数据库中的领域实体,您可以使用我们精密的仓储支持,这极大地简化了实现。为此,请为您的仓储创建一个接口。考虑以下 `Person` 类

Person 实体示例
public class Person {

  @Id
  private Long id;
  private String firstname;
  private String lastname;

  // … getters and setters omitted
}

以下示例显示了前面 `Person` 类的仓储接口

用于持久化 Person 实体的基本仓储接口
public interface PersonRepository extends ReactiveCrudRepository<Person, Long> {

  // additional custom query methods go here
}

要配置 R2DBC 仓储,您可以使用 `@EnableR2dbcRepositories` 注解。如果未配置基本包,则基础结构将扫描带注解的配置类的包。以下示例显示如何对仓储使用 Java 配置

仓储的 Java 配置
@Configuration
@EnableR2dbcRepositories
class ApplicationConfig extends AbstractR2dbcConfiguration {

  @Override
  public ConnectionFactory connectionFactory() {
    return …
  }
}

因为我们的领域仓储扩展了 `ReactiveCrudRepository`,所以它为您提供了访问实体的响应式 CRUD 操作。在 `ReactiveCrudRepository` 之上,还有 `ReactiveSortingRepository`,它添加了类似于 `PagingAndSortingRepository` 的额外排序功能。使用仓储实例仅仅是将其依赖注入到客户端的问题。因此,您可以使用以下代码检索所有 `Person` 对象

Person 实体的分页访问
@ExtendWith(SpringExtension.class)
@ContextConfiguration
class PersonRepositoryTests {

  @Autowired
  PersonRepository repository;

  @Test
  void readsAllEntitiesCorrectly() {

    repository.findAll()
      .as(StepVerifier::create)
      .expectNextCount(1)
      .verifyComplete();
  }

  @Test
  void readsEntitiesByNameCorrectly() {

    repository.findByFirstname("Hello World")
      .as(StepVerifier::create)
      .expectNextCount(1)
      .verifyComplete();
  }
}

前面的示例使用 Spring 的单元测试支持创建了一个应用程序上下文,该上下文将基于注解的依赖注入执行到测试用例中。在测试方法内部,我们使用仓储来查询数据库。我们使用 `StepVerifier` 作为测试辅助工具来根据结果验证我们的期望。

结果映射

返回接口或 DTO 投影的查询方法由实际查询产生的结果支持。接口投影通常依赖于首先将结果映射到领域类型以考虑潜在的 `@Column` 类型映射,并且实际的投影代理使用潜在的部分物化的实体来公开投影数据。

DTO 投影的结果映射取决于实际的查询类型。派生查询使用领域类型来映射结果,并且 Spring Data 仅根据领域类型上可用的属性创建 DTO 实例。不支持在 DTO 中声明领域类型上不可用的属性。

基于字符串的查询使用不同的方法,因为实际的查询(特别是字段投影)和结果类型声明紧密结合在一起。与用 `@Query` 注解的查询方法一起使用的 DTO 投影会将查询结果直接映射到 DTO 类型。不会考虑领域类型的字段映射。直接使用 DTO 类型,您的查询方法可以受益于不受限于领域模型的更动态的投影。

使用多个数据库

当使用多个(可能是不同的)数据库时,您的应用程序将需要不同的配置方法。提供的 `AbstractR2dbcConfiguration` 支持类假设单个 `ConnectionFactory`,从中派生 `Dialect`。也就是说,您需要自己定义一些 bean 来配置 Spring Data R2DBC 以使用多个数据库。

R2DBC 仓储需要 `R2dbcEntityOperations` 来实现仓储。一个简单的配置,无需使用 `AbstractR2dbcConfiguration` 即可扫描仓储,如下所示

@Configuration
@EnableR2dbcRepositories(basePackages = "com.acme.mysql", entityOperationsRef = "mysqlR2dbcEntityOperations")
static class MySQLConfiguration {

    @Bean
    @Qualifier("mysql")
    public ConnectionFactory mysqlConnectionFactory() {
        return …
    }

    @Bean
    public R2dbcEntityOperations mysqlR2dbcEntityOperations(@Qualifier("mysql") ConnectionFactory connectionFactory) {

        DatabaseClient databaseClient = DatabaseClient.create(connectionFactory);

        return new R2dbcEntityTemplate(databaseClient, MySqlDialect.INSTANCE);
    }
}

请注意,`@EnableR2dbcRepositories` 允许通过 `databaseClientRef` 或 `entityOperationsRef` 进行配置。当连接到相同类型的多个数据库时,使用各种 `DatabaseClient` bean 是很有用的。当使用方言不同的不同数据库系统时,请改用 `@EnableR2dbcRepositories(entityOperationsRef = …)`。