このガイドでは、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;
  }
}

Here you have a Customer class with three attributes: id, firstName , and lastName . You also have two constructors. The default constructor exists only for the sake of JPA. You do not use it directly, so it is designated as protected . The other constructor is the one you use to create instances of Customer to be saved to the database.

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

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

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

便利な 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);
}

CustomerRepositoryCrudRepository インターフェースを継承します。動作するエンティティのタイプとID Customer および Longは、CrudRepositoryの汎用パラメーターで指定されます。 CrudRepository, CustomerRepository を継承すると、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クリエイティブコモンズライセンス(英語) でリリースされています。