JPA でインメモリ H2 データアクセス

このガイドでは、Spring Data JPA を使用してリレーショナルデータベースにデータを保存および取得するアプリケーションを構築するプロセスを順を追って説明します。

構築するもの

メモリベースのデータベースに Customer オブジェクトを保存するアプリケーションを構築します。

必要なもの

本ガイドの完成までの流れ

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

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

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

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

Spring Initializr から開始

IDE を使用する場合はプロジェクト作成ウィザードを使用します。IDE を使用せずにコマンドラインなどで開発する場合は、この事前に初期化されたプロジェクトからプロジェクトを ZIP ファイルとしてダウンロードできます。このプロジェクトは、このチュートリアルの例に合うように構成されています。

プロジェクトを手動で初期化するには:

  1. IDE のメニューまたはブラウザーから Spring Initializr を開きます。アプリケーションに必要なすべての依存関係を取り込み、ほとんどのセットアップを行います。

  2. Gradle または Maven のいずれかと、使用する言語を選択してください。

  3. 「アーティファクト」フォームフィールドに "accessing-data-jpa" と入力します。

  4. 依存関係をクリックし、Spring Data JPA、H2 Database の順に選択します。

  5. 生成をクリックします。

  6. 結果の ZIP ファイルをダウンロードします。これは、選択して構成された Web アプリケーションのアーカイブです。

Eclipse や IntelliJ のような IDE は新規プロジェクト作成ウィザードから Spring Initializr の機能が使用できるため、手動での ZIP ファイルのダウンロードやインポートは不要です。
プロジェクトを GitHub からフォークして、IDE または他のエディターで開くこともできます。

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

この例では、それぞれが JPA エンティティとしてアノテーションされた Customer オブジェクトを格納します。次のリストは Customer クラスを示しています。

Java
package com.example.accessingdatajpa;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;

@Entity
public class Customer {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Long id;
    private String firstName;
    private String lastName;

    protected Customer() {}

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

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

    public Long getId() {
        return id;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }
}
Kotlin
package com.example.accessingdatajpa

import jakarta.persistence.Entity
import jakarta.persistence.GeneratedValue
import jakarta.persistence.GenerationType
import jakarta.persistence.Id

@Entity
class Customer(
    var firstName: String = "",
    var lastName: String = ""
) {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    var id: Long? = null

    override fun toString(): String =
        "Customer[id=$id, firstName='$firstName', lastName='$lastName']"
}

ここに、id、firstName、lastName という 3 つの属性を持つ Customer クラスがあります。また、2 つのコンストラクターがあります。デフォルトのコンストラクターは、JPA のためにのみ存在します。直接使用しないため、protected と表記します。もう 1 つのコンストラクターは、データベースに保存する Customer のインスタンスを作成するために使用するコンストラクターです。

Customer クラスには @Entity のアノテーションが付けられており、JPA エンティティであることを示しています。(@Table アノテーションが存在しないため、このエンティティは Customer という名前のテーブルにマッピングされると想定されます。)

Customer オブジェクトの id プロパティには @Id のアノテーションが付けられているため、JPA はそれをオブジェクトの ID として認識します。id プロパティにも @GeneratedValue のアノテーションが付けられ、ID が自動的に生成されることを示します。

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

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

単純なクエリを作成する

Spring Data JPA は、JPA を使用してリレーショナルデータベースにデータを保存することに焦点を当てています。その最も魅力的な機能は、実行時にリポジトリインターフェースからリポジトリ実装を自動的に作成する機能です。

これがどのように機能するかを確認するには、次のように、Customer エンティティで機能するリポジトリインターフェースを作成します。

Java
package com.example.accessingdatajpa;

import java.util.List;

import org.springframework.data.repository.CrudRepository;

public interface CustomerRepository extends CrudRepository<Customer, Long> {

    List<Customer> findByLastName(String lastName);

    Customer findById(long id);
}
Kotlin
package com.example.accessingdatajpa

import org.springframework.data.repository.CrudRepository

interface CustomerRepository : CrudRepository<Customer, Long> {
    fun findByLastName(lastName: String): List<Customer>
}

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

Spring Data JPA では、メソッドシグネチャーを宣言することにより、他のクエリメソッドを定義することもできます。例: CustomerRepository には findByLastName() メソッドが含まれています。

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

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

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

Spring Initializr は、アプリケーション用のシンプルなクラスを作成します。以下のリストは、この例のために Initializr が作成したクラスを示しています。

Java
package com.example.accessingdatajpa;

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

@SpringBootApplication
public class AccessingDataJpaApplication {

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

}
Kotlin
package com.example.accessingdatajpa

import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication

@SpringBootApplication
class AccessingDataJpaApplication

fun main(args: Array<String>) {
    runApplication<AccessingDataJpaApplication>(*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 が作成したシンプルなクラスを修正する必要があります。出力(この例ではコンソール)を取得するには、ロガーを設定する必要があります。次に、いくつかのデータを設定し、それを使用して出力を生成する必要があります。完成した AccessingDataJpaApplication クラスを以下に示します。

Java
package com.example.accessingdatajpa;

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;

@SpringBootApplication
public class AccessingDataJpaApplication {

    private static final Logger logger = LoggerFactory.getLogger(AccessingDataJpaApplication.class);

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

    @Bean
    public CommandLineRunner demo(CustomerRepository repository) {
        return (args) -> {
            // save a few customers
            repository.save(new Customer("Jack", "Bauer"));
            repository.save(new Customer("Chloe", "O'Brian"));
            repository.save(new Customer("Kim", "Bauer"));
            repository.save(new Customer("David", "Palmer"));
            repository.save(new Customer("Michelle", "Dessler"));

            // fetch all customers
            logger.info("Customers found with findAll():");
            logger.info("-------------------------------");
            repository.findAll().forEach(customer -> {
                logger.info(customer.toString());
            });
            logger.info("");

            // fetch an individual customer by ID
            Customer customer = repository.findById(1L);
            logger.info("Customer found with findById(1L):");
            logger.info("--------------------------------");
            logger.info(customer.toString());
            logger.info("");

            // fetch customers by last name
            logger.info("Customer found with findByLastName('Bauer'):");
            logger.info("--------------------------------------------");
            repository.findByLastName("Bauer").forEach(bauer -> {
                logger.info(bauer.toString());
            });
            logger.info("");
        };
    }

}
Kotlin
package com.example.accessingdatajpa

import org.slf4j.LoggerFactory
import org.springframework.boot.CommandLineRunner
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.context.annotation.Bean

private val logger = LoggerFactory.getLogger(AccessingDataJpaApplication::class.java)

@SpringBootApplication
class AccessingDataJpaApplication {

    @Bean
    fun demo(repository: CustomerRepository) = CommandLineRunner {
        // save a few customers
        repository.saveAll(
            listOf(
                Customer("Jack", "Bauer"),
                Customer("Chloe", "O'Brian"),
                Customer("Kim", "Bauer"),
                Customer("David", "Palmer"),
                Customer("Michelle", "Dessler")
            )
        )

        // fetch all customers
        logger.info("Customers found with findAll():")
        logger.info("-------------------------------")
        repository.findAll().forEach { customer ->
            logger.info(customer.toString())
        }
        logger.info("")

        // fetch an individual customer by ID
        val customer = repository.findById(1L).orElseThrow()
        logger.info("Customer found with findById(1L):")
        logger.info("--------------------------------")
        logger.info(customer.toString())
        logger.info("")

        // fetch customers by last name
        logger.info("Customer found with findByLastName('Bauer'):")
        logger.info("--------------------------------------------")
        repository.findByLastName("Bauer").forEach { bauer ->
            logger.info(bauer.toString())
        }
        logger.info("")
    }
}

fun main(args: Array<String>) {
    runApplication<AccessingDataJpaApplication>(*args)
}

AccessingDataJpaApplication クラスには、CustomerRepository をいくつかのテストにかける demo() メソッドが含まれています。まず、Spring アプリケーションコンテキストから CustomerRepository をフェッチします。次に、Customer オブジェクトをいくつか保存して、save() メソッドを示し、操作するデータを設定します。次に、findAll() を呼び出して、データベースからすべての Customer オブジェクトをフェッチします。次に、findById() を呼び出して、その ID で単一の Customer をフェッチします。最後に、findByLastName() を呼び出して、姓が "Bauer" であるすべての顧客を検索します。demo() メソッドは、アプリケーションの起動時にコードを自動的に実行する CommandLineRunner Bean を返します。

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

実行可能 JAR を構築する

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

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

java -jar build/libs/gs-accessing-data-jpa-0.0.1-SNAPSHOT.jar

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

java -jar target/gs-accessing-data-jpa-0.0.1-SNAPSHOT.jar

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

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 findById(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 JPA を使用してオブジェクトをデータベースに保存したり、データベースからフェッチしたりする単純なアプリケーションを作成しました。

ハイパーメディアベースの RESTful フロントエンドで JPA リポジトリを簡単に公開したい場合は、Spring Data REST API の自動生成 (JPA) を読むことをお勧めします。

関連事項

次のガイドも役立つかもしれません:

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

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

コードを入手する

FREE

クラウドでの作業

Spring アカデミーのクラウドでガイドを完成させよう。

Spring アカデミーへ

プロジェクト