JPA で MySQL データアクセス

このガイドでは、MySQL データベースに接続された Spring アプリケーションを作成するプロセスを順を追って説明します(他のほとんどのガイドや多くのサンプルアプリケーションが使用するインメモリの組み込みデータベースとは対照的です)。Spring Data JPA を使用してデータベースにアクセスしますが、これは多くの選択肢のうちの 1 つにすぎません(たとえば、プレーンな Spring JDBC を使用できます)。

構築するもの

MySQL データベースを作成し、Spring アプリケーションを構築して、新しく作成したデータベースに接続します。

MySQL は GPL でライセンスされているため、配布するプログラムバイナリも GPL を使用する必要があります。GNU 一般公衆利用許諾契約書 (英語) を参照してください。

必要なもの

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

ほとんどの Spring 入門ガイドと同様に、最初から始めて各ステップを完了することも、このリポジトリ [GitHub] (英語) のコードを確認してソリューションに直接進むこともできます。

ローカル環境で最終結果を確認するには、次のいずれかを実行します。

MySQL データベースの設定

アプリケーションをビルドする前に、まず MySQL データベースを構成する必要があります。このガイドでは、Spring Boot Docker Compose サポートを使用することを前提としています。このアプローチの前提条件は、開発マシンに Docker デスクトップ (英語) などの Docker 環境が利用可能であることです。次の操作を実行する依存関係 spring-boot-docker-compose を追加します。

  • 作業ディレクトリで compose.yml やその他の一般的な compose ファイル名を検索します

  • 検出された compose.yml を使用して docker compose up を呼び出します

  • サポートされているコンテナーごとにサービス接続 Bean を作成する

  • アプリケーションのシャットダウン時に docker compose stop を呼び出します

Docker Compose サポートを使用するには、このガイドに従うだけです。取り込んだ依存関係に基づいて、Spring Boot は正しい compose.yml ファイルを見つけ、アプリケーションの実行時に Docker コンテナーを起動します。

Spring Initializr から開始

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

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

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

  2. Gradle または Maven のいずれかと、使用する言語を選択します。このガイドは、Java を選択したことを前提としています。

  3. 依存関係をクリックし、Spring Web、Spring Data JPA、MySQL ドライバー、Docker Compose サポート、Testcontainers を選択します。

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

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

Eclipse や IntelliJ のような IDE は新規プロジェクト作成ウィザードから Spring Initializr の機能が使用できるため、手動での ZIP ファイルのダウンロードやインポートは不要です。

@Entity モデルを作成する

次のリスト(src/main/java/com/example/accessingdatamysql/User.java)に示すように、エンティティモデルを作成する必要があります。

package com.example.accessingdatamysql;

import org.jspecify.annotations.Nullable;

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

@Entity // This tells Hibernate to make a table out of this class
public class User {
  @Id
  @GeneratedValue(strategy=GenerationType.AUTO)
  private @Nullable Integer id;

  private String name;

  private String email;

  public Integer getId() {
    return id;
  }

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

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public String getEmail() {
    return email;
  }

  public void setEmail(String email) {
    this.email = email;
  }
}

Hibernate は、エンティティを自動的にテーブルに変換します。

リポジトリを作成する

次のリスト(src/main/java/com/example/accessingdatamysql/UserRepository.java)に示すように、ユーザーレコードを保持するリポジトリを作成する必要があります。

package com.example.accessingdatamysql;

import org.springframework.data.repository.CrudRepository;

// This will be AUTO IMPLEMENTED by Spring into a Bean called userRepository
// CRUD refers Create, Read, Update, Delete

public interface UserRepository extends CrudRepository<User, Integer> {

}

Spring は、同じリポジトリの Bean にこのリポジトリインターフェースを自動的に実装します(ケースに変更があります。userRepository と呼ばれます)。

コントローラーの作成

次のリスト(src/main/java/com/example/accessingdatamysql/MainController.java)に示すように、アプリケーションへの HTTP リクエストを処理するコントローラーを作成する必要があります。

package com.example.accessingdatamysql;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller // This means that this class is a Controller
@RequestMapping(path="/demo") // This means URL's start with /demo (after Application path)
public class MainController {
  @Autowired // This means to get the bean called userRepository
         // Which is auto-generated by Spring, we will use it to handle the data
  private UserRepository userRepository;

  @PostMapping(path="/add") // Map ONLY POST Requests
  public @ResponseBody String addNewUser (@RequestParam String name
      , @RequestParam String email) {
    // @ResponseBody means the returned String is the response, not a view name
    // @RequestParam means it is a parameter from the GET or POST request

    User n = new User();
    n.setName(name);
    n.setEmail(email);
    userRepository.save(n);
    return "Saved";
  }

  @GetMapping(path="/all")
  public @ResponseBody Iterable<User> getAllUsers() {
    // This returns a JSON or XML with the users
    return userRepository.findAll();
  }
}
上記の例では、2 つのエンドポイントに POST と GET を明示的に指定しています。デフォルトでは、@RequestMapping はすべての HTTP 操作をマップします。

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

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

package com.example.accessingdatamysql;

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

@SpringBootApplication
public class AccessingDataMysqlApplication {

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

}

この例では、AccessingDataMysqlApplication クラスを変更する必要はありません。

Spring Initializr は、メインクラスに @SpringBootApplication アノテーションを追加します。@SpringBootApplication は、次のすべてを追加する便利なアノテーションです。

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

  • @EnableAutoConfiguration: Spring Boot は、追加した依存関係に基づいて、Spring アプリケーションを自動的に構成しようとします。

  • @ComponentScan: Spring に他のコンポーネント、構成、サービスを検索するように指示します。特定のパッケージが定義されていない場合は、アノテーションを宣言するクラスのパッケージから再帰スキャンが開始されます。

アプリケーションの実行

この時点で、アプリケーションを実行して、コードの動作を確認できます。メインメソッドは、IDE またはコマンドラインから実行できます。ソリューションリポジトリからプロジェクトをクローンした場合、IDE が compose.yaml ファイルを間違った場所で探す可能性があることに注意してください。IDE を構成して正しい場所を探すか、コマンドラインを使用してアプリケーションを実行できます。./gradlew bootRun コマンドと ./mvnw spring-boot:run コマンドは、アプリケーションを起動し、compose.yaml ファイルを自動的に見つけます。

アプリケーションをテストする

アプリケーションが実行されたため、curl または同様のツールを使用してテストできます。テストできる 2 つの HTTP エンドポイントがあります。

GET localhost:8080/demo/all: すべてのデータを取得します。POST localhost:8080/demo/add: 1 人のユーザーをデータに追加します。

次の curl コマンドは、ユーザーを追加します。

$ curl http://localhost:8080/demo/add -d name=First -d [email protected] (英語)  

返信は次のようになります。

Saved

次のコマンドは、すべてのユーザーを表示します。

$ curl http://localhost:8080/demo/all

返信は次のようになります。

[{"id":1,"name":"First","email":"[email protected] (英語)  "}]

実行可能 JAR を構築する

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

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

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

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

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

実行可能 JAR を java -jar コマンドで実行すると、docker compose のサポートは利用できなくなります。compose.yaml で定義された MYSQL コンテナーに接続できるように、アプリを更新する必要があります。

まず、3306 ポートをコンテナー外に公開する必要があります。compose.yaml を編集し、ports セクションを 3306:3306 に合わせて変更します。最終的な結果は次のようになります。

services:
  mysql:
    image: 'mysql:8.4.7'
    environment:
      - 'MYSQL_DATABASE=mydatabase'
      - 'MYSQL_PASSWORD=secret'
      - 'MYSQL_ROOT_PASSWORD=verysecret'
      - 'MYSQL_USER=myuser'
    ports:
      - '3306:3306'

次に、アプリケーションをデータベースに接続するための設定が必要です。URL、ユーザー名、パスワードは、docker サービス設定の資格情報と一致している必要があります。また、必要に応じて、起動時にデータベースを作成(または更新)するように spring.jpa.hibernate.ddl-auto を設定する必要があります。

spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

spring.datasource.url=jdbc:mysql://${MYSQL_HOST:localhost}:3306/mydatabase
spring.datasource.username=myuser
spring.datasource.password=secret

アプリケーションを実行する前に、Spring Boot の docker compose では MySQL コンテナーを起動できなくなったため、MySQL コンテナーも起動する必要があります。

docker compose up -d

その後、アプリケーションをテストするに従って、curl コマンドを実行できます。

セキュリティを変更する

本番環境では、SQL インジェクション攻撃にさらされる可能性があります。ハッカーは DROP TABLE またはその他の破棄的な SQL コマンドを挿入する可能性があります。セキュリティ対策として、アプリケーションをユーザーに公開する前に、データベースにいくつかの変更を加える必要があります。

次のコマンドは、Spring アプリケーションに関連付けられているユーザーからすべての特権を取り消します。

mysql> revoke all on mydatabase.* from 'myuser'@'%';

これで、Spring アプリケーションはデータベースで何もできなくなりました。

アプリケーションには何らかの特権が必要であるため、次のコマンドを使用して、アプリケーションに必要な最小限の特権を付与します。

mysql> grant select, insert, delete, update on mydatabase.* to 'myuser'@'%';

すべての特権を削除して一部の特権を付与すると、Spring アプリケーションに、構造(スキーマ)ではなくデータベースのデータのみを変更するために必要な特権が付与されます。

データベースに変更を加える場合:

  1. 許可を再付与します。

  2. spring.jpa.hibernate.ddl-auto を update に変更します。

  3. アプリケーションを再実行します。

次に、ここに示す 2 つのコマンドを繰り返して、アプリケーションを再び本番環境で安全に使用できるようにします。さらに良い方法は、Flyway や Liquibase などの専用の移行ツールを使用することです。

要約

おめでとう! MySQL データベースにバインドされた Spring アプリケーションを開発し、本番の準備ができました!

関連事項

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

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

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

コードを入手する