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

構築するもの

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

何が必要

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

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

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

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

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

Spring Initializr から開始

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

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

次のリストは、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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>accessing-data-jpa</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>accessing-data-jpa</name>
    <description>Demo project for Spring Boot</description>

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

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>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>
    </dependencies>

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

</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()
}

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

test {
    useJUnitPlatform()
}

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

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

package com.example.accessingdatajpa;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.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;
  }
}

ここに、idfirstName および 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 を使用してリレーショナルデータベースにデータを保存することに焦点を当てています。その最も魅力的な機能は、実行時にリポジトリインターフェースからリポジトリ実装を自動的に作成する機能です。

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

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);
}

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

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

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

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

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

Spring Initializr は、アプリケーションの単純なクラスを作成します。次のリストは、Initializr がこの例(src/main/java/com/example/accessingdatajpa/AccessingDataJpaApplication.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);
  }

}

@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 クラス(src/main/java/com/example/accessingdatajpa/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 log = LoggerFactory.getLogger(AccessingDataJpaApplication.class);

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

  @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
      log.info("Customers found with findAll():");
      log.info("-------------------------------");
      for (Customer customer : repository.findAll()) {
        log.info(customer.toString());
      }
      log.info("");

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

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

}

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

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

デフォルトでは、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.1.0.jar

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

java -jar target/gs-accessing-data-jpa-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 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 リポジトリを簡単に公開したい場合は、REST で JPA データアクセスを読むことをお勧めします。

関連事項

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

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

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