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

構築するもの

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

MySQL は GPL でライセンスされているため、配布するプログラムバイナリも GPL を使用する必要があります。GNU General Public License (英語) を参照してください。

必要なもの

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

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

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

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

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

Spring Initializr から開始

すべての Spring アプリケーションでは、Spring Initializr (英語) から始める必要があります。Initializr は、アプリケーションに必要なすべての依存関係をすばやく取り込む方法を提供し、多くの設定を行います。この例では、Spring Web Starter、Spring Data JPA、および MySQL ドライバーの依存関係が必要です。

次のリストは、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.3.2.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>accessing-data-mysql</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>accessing-data-mysql</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>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</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.3.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'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	runtimeOnly 'mysql:mysql-connector-java'
	testImplementation('org.springframework.boot:spring-boot-starter-test') {
		exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
	}
}

test {
	useJUnitPlatform()
}

データベースを作成する

ターミナル(Microsoft Windows のコマンドプロンプト)を開き、新しいユーザーを作成できるユーザーとして MySQL クライアントを開きます。

例:Linux システムでは、次のコマンドを使用します。

$ sudo mysql --password
これは root として MySQL に接続し、すべてのホストからユーザーへのアクセスを許可します。これは、運用サーバーに推奨される方法ではありません。

新しいデータベースを作成するには、mysql プロンプトで次のコマンドを実行します。

mysql> create database db_example; -- Creates the new database
mysql> create user 'springuser'@'%' identified by 'ThePassword'; -- Creates the user
mysql> grant all on db_example.* to 'springuser'@'%'; -- Gives all privileges to the new user on the newly created database

application.properties ファイルを作成する

Spring Boot は、すべてのデフォルトを提供します。例:デフォルトのデータベースは H2 です。他のデータベースを使用する場合は、application.properties ファイルで接続属性を定義する必要があります。

次のリストに示すように、src/main/resources/application.properties というリソースファイルを作成します。

spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:mysql://${MYSQL_HOST:localhost}:3306/db_example
spring.datasource.username=springuser
spring.datasource.password=ThePassword

ここで、spring.jpa.hibernate.ddl-auto は noneupdatecreate または create-drop になります。詳細については、Hibernate のドキュメント (英語) を参照してください。

  • noneMySQL のデフォルト。データベース構造は変更されません。

  • update: Hibernate は、指定されたエンティティ構造に従ってデータベースを変更します。

  • create: データベースを毎回作成しますが、閉じるときに削除しません。

  • create-drop: データベースを作成し、SessionFactory が閉じたときにデータベースを削除します。

データベース構造がまだないため、create または update で始める必要があります。最初の実行後、プログラムの要件に応じて、update または none に切り替えることができます。データベース構造に何らかの変更を加える場合は、update を使用します。

H2 およびその他の組み込みデータベースのデフォルトは create-drop です。MySQL などの他のデータベースの場合、デフォルトは none です。

データベースが本番状態になった後、これを none に設定し、Spring アプリケーションに接続されている MySQL ユーザーからすべての特権を取り消し、MySQL ユーザーに SELECTUPDATEINSERT および DELETE のみを付与することは、セキュリティ上の良い習慣です。詳細については、このガイドの最後を参照してください。

@Entity モデルを作成する

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

package com.example.accessingdatamysql;

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

@Entity // This tells Hibernate to make a table out of this class
public class User {
  @Id
  @GeneratedValue(strategy=GenerationType.AUTO)
  private 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;

import com.example.accessingdatamysql.User;

// 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 クラスを変更する必要はありません。

@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 であり、接続機能やインフラストラクチャの構成に対処する必要はありませんでした。

実行可能 JAR を構築する

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

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

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

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

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

アプリケーションを実行すると、ログ出力が表示されます。サービスは数秒以内に起動して実行されるはずです。

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

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

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

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

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

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

Saved

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

$ curl 'localhost:8080/demo/all'

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

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

セキュリティを変更する

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

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

mysql> revoke all on db_example.* from 'springuser'@'%';

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

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

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

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

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

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

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

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

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

要約

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

関連事項

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

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

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