🚀 Spring Framework 講座【特別編】高性能なデータアクセス!〜R2DBCとリアクティブなDB接続〜

docs

前回、AWS LambdaSpring Cloud Functionを使ったサーバーレス環境へのデプロイを学びました。これらのノンブロッキングな環境でシステムの性能を最大限に引き出すためには、データアクセス層もリアクティブである必要があります。

これまでの講座で使ってきた Spring Data JPA は、裏側でJDBC(Java Database Connectivity)を使っており、これは本質的に**ブロッキング(同期I/O)**処理です。ControllerやService層がノンブロッキング(WebFlux)であっても、DBアクセスでスレッドがブロックされてしまうと、その性能上の利点は失われてしまいます。

今回は、このボトルネックを解消するための新しいデータアクセス技術 **R2DBC(Reactive Relational Database Connectivity)**と、Spring Bootでの使い方を学びます。


1. R2DBCとは?

R2DBC は、リレーショナルデータベース(RDB)接続のためのリアクティブな(ノンブロッキングな)ドライバー仕様です。これは、従来の JDBC をリアクティブ環境に適応させるためにゼロから設計されました。

  • 課題: JDBCは設計上スレッドをブロックするように作られており、WebFlux(第48回)環境で利用すると、そのノンブロッキングのメリットを失ってしまいます。
  • R2DBCの解決策: R2DBCは、データアクセス中にスレッドをブロックせず、データが利用可能になったらイベントとして通知する仕組みを採用しています。これにより、WebFlux環境全体で一貫したノンブロッキングなデータフローが実現し、スレッド利用効率が大幅に向上します。

2. Spring Data R2DBCの導入

Spring BootアプリケーションでR2DBCを利用するには、専用のスターターと対応するデータベースドライバーが必要です。

2-1. 依存関係の追加

プロジェクトに、Spring Data R2DBCのスターターと、対象DB(例:PostgreSQL)のR2DBCドライバーを追加します。

Groovy

dependencies {
    // WebFluxのスターター(リアクティブ環境の基盤)
    implementation 'org.springframework.boot:spring-boot-starter-webflux'
    
    // Spring Data R2DBCのスターター
    implementation 'org.springframework.boot:spring-boot-starter-data-r2dbc'
    
    // PostgreSQLのR2DBCドライバー
    runtimeOnly 'io.r2dbc:r2dbc-postgresql' 
    
    // ...
}

2-2. 設定の変更

従来のJDBC接続設定(spring.datasource.urlなど)の代わりに、R2DBC用の接続URLを設定します。

YAML

spring:
  r2dbc:
    # URLのスキーマが 'r2dbc' で始まる
    url: r2dbc:postgresql://localhost:5432/myapp_db
    username: user
    password: password

3. リアクティブなデータアクセスの実装

Spring Data R2DBCでは、従来のJPAと同様にRepositoryインターフェースを定義しますが、使用するインターフェースと戻り値の型が異なります。

3-1. エンティティの定義

エンティティクラスはJPAとほぼ同じですが、jakarta.persistence の代わりに org.springframework.data.annotation.Id を使います。

Java

import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.Table;
import lombok.Data;

@Data
@Table("items") // R2DBCでは @Table を使用
public class Item {
    
    @Id // R2DBCでは @Id を使用
    private Long id;
    private String name;
    private Integer stock;
    // ...
}

3-2. リアクティブなRepository

JpaRepository の代わりに R2dbcRepository を継承します。すべてのメソッドの戻り値は、非同期なデータフローを表現する Mono または Flux(第48回)になります。

Java

import org.springframework.data.r2dbc.repository.R2dbcRepository;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

public interface ItemRepository extends R2dbcRepository<Item, Long> {
    
    // findByIdの戻り値は Mono<Item>
    Mono<Item> findByName(String name); 
    
    // findAllの戻り値は Flux<Item>
    Flux<Item> findByStockGreaterThan(Integer stock); 
}

4. Service層とController層での連携

Service層では、Repositoryから返されるMono/Fluxをメソッドチェーンで繋ぎ、非同期処理を継続させます。

Java

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;

@Service
@RequiredArgsConstructor
public class ItemService {
    
    private final ItemRepository itemRepository;

    public Mono<Item> createNewItem(String name) {
        // Mono<Item> を返し、DB処理をブロックしない
        Item newItem = new Item(name, 0); 
        return itemRepository.save(newItem);
    }

    public Mono<Item> getItem(Long id) {
        // DBから取得し、結果が返ってくるまでスレッドはブロックされない
        return itemRepository.findById(id)
                .switchIfEmpty(Mono.error(new ItemNotFoundException("商品が見つかりません")));
    }
}

Controller層でもMono/Fluxをそのまま返せば、WebFluxがノンブロッキングな形でレスポンスを組み立て、クライアントに返送します。

5. まとめ:未来志向のデータアクセス

R2DBCは、Spring Data JPAと比べて歴史は浅いですが、WebFluxを採用するアプリケーションにとっては、性能のボトルネックを完全に解消する必須の技術です。高性能、高スループットを求めるモダンなシステム設計において、R2DBCはデータベースアクセスにおける未来の標準となるでしょう。

✅ 本日のまとめ

  • R2DBCは、従来のJDBCが持つ**ブロッキング(同期I/O)の課題を解決し、RDB接続をリアクティブな(ノンブロッキングな)**データフローにするための仕様である。
  • R2DBCを利用することで、WebFlux環境全体でスレッドをブロックすることなく、高スループットを実現できる。
  • Spring Data R2DBCでは R2dbcRepository を継承し、すべてのデータアクセスメソッドは Mono または Flux を返す。
  • R2DBC環境でのデータアクセスは、Service層でMono/Fluxのメソッドチェーンを繋げる形で実装される。

【Spring Framework 50回講座 完】 📖✨

コメント

タイトルとURLをコピーしました