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 に加えて、PagingAndSortingRepository と同様のソート機能を追加する ReactiveSortingRepository もあります。リポジトリインスタンスの操作は、それをクライアントに挿入する依存関係の問題にすぎません。次のコードですべての 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 サポートクラスは、Dialect が派生する単一の ConnectionFactory を想定しています。そうは言っても、複数のデータベースで動作するように Spring Data R2DBC を構成するには、いくつかの Bean を自分で定義する必要があります。

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 = …) を使用します。