このガイドでは、Spring Data R2DBC を使用してリアクティブデータベースドライバーを使用してリレーショナルデータベースにデータを格納および取得するアプリケーションを構築するプロセスを順を追って説明します。仕様の詳細は、Spring Data R2DBC リファレンスドキュメントを参照してください。

構築する

Customer POJO(Plain Old Java Objects)をメモリベースのデータベースに保存するアプリケーションを構築します。

必要なもの

このガイドを完了する方法

ほとんどの Spring 入門ガイドと同様に、最初から始めて各ステップを完了するか、すでに慣れている場合は基本的なセットアップステップをバイパスできます。いずれにしても、最終的に動作するコードになります。

最初から始めるには、Spring Initializr から開始に進みます。

基本スキップするには、次の手順を実行します。

完了したときは、gs-accessing-data-r2dbc/complete のコードに対して結果を確認できます。

Spring Initializr から開始

すべての Spring アプリケーションの場合、Spring Initializr (英語) から開始する必要があります。Initializr は、アプリケーションに必要なすべての依存関係をすばやく取り込む方法を提供し、多くのセットアップを行います。この例では、R2DBC と H2 の依存関係が必要です。次のイメージは、このサンプルプロジェクト用に設定された Initializr を示しています。

initializr
前の図は、Maven がビルドツールとして選択された Initializr を示しています。Gradle も使用できます。また、com.example および accesing-data-r2dbc の値をそれぞれグループおよびアーティファクトとして表示します。このサンプルの残りの部分では、これらの値を使用します。

次のリストは、Maven を選択したときに作成される pom.xml ファイルを示しています。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.springframework</groupId>
    <artifactId>accessing-data-r2dbc</artifactId>
    <version>0.1.0</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot.experimental</groupId>
            <artifactId>spring-boot-starter-data-r2dbc</artifactId>
        </dependency>
        <dependency>
            <groupId>io.r2dbc</groupId>
            <artifactId>r2dbc-h2</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot.experimental</groupId>
            <artifactId>spring-boot-test-autoconfigure-r2dbc</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.projectreactor</groupId>
            <artifactId>reactor-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot.experimental</groupId>
                <artifactId>spring-boot-bom-r2dbc</artifactId>
                <version>0.1.0.M3</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
        </repository>
    </repositories>

</project>

次のリストは、Gradle を選択したときに作成される build.gradle ファイルを示しています。

plugins {
	id 'org.springframework.boot' version '2.2.2.RELEASE'
	id 'io.spring.dependency-management' version '1.0.8.RELEASE'
	id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

repositories {
	mavenCentral()
	maven { url 'https://repo.spring.io/milestone' }
}

dependencies {
	implementation 'org.springframework.boot.experimental:spring-boot-starter-data-r2dbc'
	runtimeOnly 'com.h2database:h2'
	runtimeOnly 'io.r2dbc:r2dbc-h2'
	testImplementation('org.springframework.boot:spring-boot-starter-test') {
		exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
	}
	testImplementation 'org.springframework.boot.experimental:spring-boot-test-autoconfigure-r2dbc'
	testImplementation 'io.projectreactor:reactor-test'
}

dependencyManagement {
	imports {
		mavenBom 'org.springframework.boot.experimental:spring-boot-bom-r2dbc:0.1.0.M3'
	}
}

test {
	useJUnitPlatform()
}

スキーマを定義する

この例では、それぞれ R2DBC エンティティとしてアノテーションが付けられた Customer オブジェクトを保存します。次のリストは、SQL スキーマクラス(src/main/resources/schema.sql 内)を示しています。

CREATE TABLE customer (id SERIAL PRIMARY KEY, first_name VARCHAR(255), last_name VARCHAR(255));

ここに、idfirst_name および last_name の 3 つの列を持つ customer テーブルがあります。id 列は自動インクリメントされ、他の列はデフォルトのスネークケースの命名スキームに従います。Spring Boot の自動構成は、アプリケーションの起動時に schema.sql ファイルを取得して、データベーススキーマを初期化します。

単純なエンティティを定義する

この例では、それぞれ R2DBC エンティティとしてアノテーションが付けられた Customer オブジェクトを保存します。次のリストは、Customer クラス(src/main/java/com/example/accessingdatar2dbc/Customer.java 内)を示しています。

package com.example.accessingdatar2dbc;

import org.springframework.data.annotation.Id;

public class Customer {

    @Id
    private Long id;

    private final String firstName;

    private final String lastName;

    public Customer(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public Long getId() {
        return this.id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getFirstName() {
        return this.firstName;
    }

    public String getLastName() {
        return this.lastName;
    }

    @Override
    public String toString() {
        return String.format(
            "Customer[id=%d, firstName='%s', lastName='%s']",
            id, firstName, lastName);
    }
}

ここに、idfirstName および lastName の 3 つの属性を持つ Customer クラスがあります。Customer クラスには最小限のアノテーションが付けられています。id プロパティには @Id のアノテーションが付けられているため、Spring Data R2DBC は主キーを識別できます。デフォルトでは、主キーは INSERT のデータベースによって生成されると想定されています。

他の 2 つのプロパティ firstName と lastName にはアノテーションが付けられていません。これらは、プロパティ自体と同じ名前を共有する列にマップされると想定されています。

便利な toString() メソッドは、顧客のプロパティを出力します。

単純なクエリを作成する

Spring Data R2DBC は、リレーショナルデータベースにデータを格納するための基盤となるテクノロジーとして R2DBC を使用することに焦点を当てています。その最も魅力的な機能は、実行時に、リポジトリインターフェースからリポジトリ実装を作成できることです。

これがどのように機能するかを確認するには、次のリスト(src/main/java/com/example/accessingdatar2dbc/CustomerRepository.java 内)が示すように、Customer エンティティで動作するリポジトリインターフェースを作成します。

package com.example.accessingdatar2dbc;

import org.springframework.data.r2dbc.repository.Query;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;

import reactor.core.publisher.Flux;

public interface CustomerRepository extends ReactiveCrudRepository<Customer, Long> {

    @Query("SELECT * FROM customer WHERE last_name = :lastname")
    Flux<Customer> findByLastName(String lastName);

}

CustomerRepository は ReactiveCrudRepository インターフェースを継承します。動作するエンティティのタイプと ID Customer および Long は、ReactiveCrudRepository のジェネリックパラメーターで指定されます。ReactiveCrudRepositoryCustomerRepository を継承することにより、リアクティブ型を使用して Customer エンティティを保存、削除、検索する方法など、Customer 永続性を操作するためのいくつかの方法を継承します。

Spring Data R2DBC では、これらに @Query のアノテーションを付けることにより、他のクエリメソッドを定義することもできます。例: CustomerRepository には findByLastName() メソッドが含まれています。

典型的な Java アプリケーションでは、CustomerRepository を実装するクラスを作成することを期待できます。ただし、それが Spring Data R2DBC を非常に強力にしている理由です。リポジトリインターフェースの実装を記述する必要はありません。Spring Data R2DBC は、アプリケーションの実行時に実装を作成します。

これで、この例を接続して、その外観を確認できます!

アプリケーションクラスを作成する

Spring Initializr は、アプリケーションの単純なクラスを作成します。次のリストは、Initializr がこの例(src/main/java/com/example/accessingdatar2dbc/AccessingDataR2dbcApplication.java 内)で作成したクラスを示しています。

package com.example.accessingdatar2dbc;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class AccessingDataR2dbcApplication {

	public static void main(String[] args) {
		SpringApplication.run(AccessingDataR2dbcApplication.class, args);
	}

}

@SpringBootApplication は、次のすべてを追加する便利なアノテーションです。

  • @Configuration: アプリケーションコンテキストの Bean 定義のソースとしてクラスにタグを付けます。

  • @EnableAutoConfiguration: クラスパス設定、他の Bean、およびさまざまなプロパティ設定に基づいて Bean の追加を開始するよう Spring Boot に指示します。例: spring-webmvc がクラスパスにある場合、このアノテーションはアプリケーションに Web アプリケーションとしてフラグを立て、DispatcherServlet のセットアップなどの主要な動作をアクティブにします。

  • @ComponentScan: Spring に、com/example パッケージ内の他のコンポーネント、構成、およびサービスを探して、コントローラーを検出させるように指示します。

main() メソッドは、Spring Boot の SpringApplication.run() メソッドを使用してアプリケーションを起動します。XML が 1 行もないことに気付きましたか? web.xml ファイルもありません。この Web アプリケーションは 100% 純粋な Java であり、接続機能やインフラストラクチャの構成に対処する必要はありませんでした。

ここで、Initializr が作成した単純なクラスを変更する必要があります。出力を取得するには(この例ではコンソールに)、ロガーをセットアップする必要があります。次に、いくつかのデータを設定し、それを使用して出力を生成する必要があります。次のリストは、完成した AccessingDataR2dbcApplication クラス(src/main/java/com/example/accessingdatar2dbc/AccessingDataR2dbcApplication.java 内)を示しています。

package com.example.accessingdatar2dbc;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

import java.time.Duration;
import java.util.Arrays;

@SpringBootApplication
public class AccessingDataR2dbcApplication {

    private static final Logger log = LoggerFactory.getLogger(AccessingDataR2dbcApplication.class);

    public static void main(String[] args) {
        SpringApplication.run(AccessingDataR2dbcApplication.class, args);
    }

    @Bean
    public CommandLineRunner demo(CustomerRepository repository) {

        return (args) -> {
            // save a few customers
            repository.saveAll(Arrays.asList(new Customer("Jack", "Bauer"),
                new Customer("Chloe", "O'Brian"),
                new Customer("Kim", "Bauer"),
                new Customer("David", "Palmer"),
                new Customer("Michelle", "Dessler")))
                .blockLast(Duration.ofSeconds(10));

            // fetch all customers
            log.info("Customers found with findAll():");
            log.info("-------------------------------");
            repository.findAll().doOnNext(customer -> {
                log.info(customer.toString());
            }).blockLast(Duration.ofSeconds(10));

            log.info("");

            // fetch an individual customer by ID
			repository.findById(1L).doOnNext(customer -> {
				log.info("Customer found with findById(1L):");
				log.info("--------------------------------");
				log.info(customer.toString());
				log.info("");
			}).block(Duration.ofSeconds(10));


            // fetch customers by last name
            log.info("Customer found with findByLastName('Bauer'):");
            log.info("--------------------------------------------");
            repository.findByLastName("Bauer").doOnNext(bauer -> {
                log.info(bauer.toString());
            }).blockLast(Duration.ofSeconds(10));;
            log.info("");
        };
    }

}

AccessingDataR2dbcApplication クラスには、CustomerRepository をいくつかのテストにかける main() メソッドが含まれています。まず、Spring アプリケーションコンテキストから CustomerRepository をフェッチします。次に、Customer オブジェクトをいくつか保存し、save() メソッドのデモと使用するデータのセットアップを行います。次に、findAll() を呼び出して、データベースからすべての Customer オブジェクトをフェッチします。次に、findById() を呼び出して、その ID で単一の Customer をフェッチします。最後に、findByLastName() を呼び出して、姓が「Bauer」であるすべての顧客を検索します。

R2DBC は、リアクティブプログラミングテクノロジです。同時に、同期された必須のフローで使用しているため、各コールを block(…) メソッドのバリアントと同期する必要があります。通常のリアクティブアプリケーションでは、結果の Mono または Flux は、呼び出しスレッドをブロックせずにリアクティブシーケンスにサブスクライブする Web コントローラーまたはイベントプロセッサーに返されるオペレーターのパイプラインを表します。

デフォルトでは、Spring Boot は R2DBC リポジトリサポートを有効にし、@SpringBootApplication が配置されているパッケージ(およびそのサブパッケージ)を検索します。構成の R2DBC リポジトリインターフェース定義が非表示のパッケージに配置されている場合、@EnableR2dbcRepositories とそのタイプセーフ basePackageClasses=MyRepository.class パラメーターを使用して代替パッケージを指摘できます。

実行可能 JAR を構築する

コマンドラインから Gradle または Maven を使用してアプリケーションを実行できます。必要なすべての依存関係、クラス、およびリソースを含む単一の実行可能 JAR ファイルを構築して実行することもできます。実行可能な jar を構築すると、開発ライフサイクル全体、さまざまな環境などで、サービスをアプリケーションとして簡単に提供、バージョン管理、およびデプロイできます。

Gradle を使用する場合、./gradlew bootRun を使用してアプリケーションを実行できます。または、次のように、./gradlew build を使用して JAR ファイルをビルドしてから、JAR ファイルを実行できます。

java -jar build/libs/gs-accessing-data-r2dbc-0.1.0.jar

Maven を使用する場合、./mvnw spring-boot:run を使用してアプリケーションを実行できます。または、次のように、./mvnw clean package で JAR ファイルをビルドしてから、JAR ファイルを実行できます。

java -jar target/gs-accessing-data-r2dbc-0.1.0.jar
ここで説明する手順は、実行可能な JAR を作成します。クラシック WAR ファイルを作成することもできます。

アプリケーションを実行すると、次のような出力が表示されます。

== Customers found with findAll():
Customer[id=1, firstName='Jack', lastName='Bauer']
Customer[id=2, firstName='Chloe', lastName='O'Brian']
Customer[id=3, firstName='Kim', lastName='Bauer']
Customer[id=4, firstName='David', lastName='Palmer']
Customer[id=5, firstName='Michelle', lastName='Dessler']

== Customer found with findOne(1L):
Customer[id=1, firstName='Jack', lastName='Bauer']

== Customer found with findByLastName('Bauer'):
Customer[id=1, firstName='Jack', lastName='Bauer']
Customer[id=3, firstName='Kim', lastName='Bauer']

要約

おめでとう! Spring Data R2DBC を使用してデータベースにオブジェクトを保存したり、データベースからオブジェクトを取得したりする単純なアプリケーションを作成しましたが、すべて具体的なリポジトリ実装を作成する必要はありません。

関連事項

次のガイドも役立ちます。

新しいガイドを作成したり、既存のガイドに貢献したいですか? 投稿ガイドラインを参照してください (GitHub)

すべてのガイドは、コード用の ASLv2 ライセンス、およびドキュメント用の Attribution、NoDerivatives クリエイティブコモンズライセンス (英語) でリリースされています。