MySQLでテーブルを生成する-SpringBoot入門③

SpringBoot(Todo):サムネイル画像3 Todoアプリ(SpringBoot)

前回は SQL テーブルの構成を ER 図を用いて定義しました。

今回は MySQL 上にテーブルを生成します。

DB起動の準備

単に SQL ファイルを直置きしても無視されるだけなので、SQL ファイルを MySQL にロードしてもらうための事前準備を行います。

Dockerコンテナを起動

compose.yaml を開いてください。

SpringBootでTodo開発:参考画像1

現状だと十分な設定がなされていないので、下記内容に変更します。

services:
  mysql:
    container_name: mysql
    image: 'mysql:8.1.0'
    environment:
      - 'MYSQL_DATABASE=tododatabase'
      - 'MYSQL_PASSWORD=secret'
      - 'MYSQL_ROOT_PASSWORD=verysecret'
      - 'MYSQL_USER=myuser'
    volumes:
      - mysqldata:/var/lib/mysql
    ports:
      - "3306:3306"
  adminer:
    container_name: adminer
    hostname: adminer
    image: adminer:latest
    restart: always
    ports:
      - 8000:8080
    depends_on:
      - mysql
volumes:
  mysqldata:
    name: db_volume

下記変更を適用しました。

  1. MySQL のバージョンを 8.1.0 に変更
  2. DB 管理ツール「Adminer」を追加
  3. volume を「mysqldata」として定義

1のバージョン変更は、後半で扱う Flyway というライブラリが MySQL 8.1 までしか対応していないので、それに合わせています。

2の Adminer は、データベースの中身を容易に把握するために、ブラウザ上で使用するツールです。

3のボリューム定義は、データベースの最新状態をセーブしておく volume を「mysqldata」として定義しています。

volume を設定しない場合、コンテナを停止する度にデータベースの状態が初期化されてしまいます。

次に、「Ctrl」+「Esc」を押して「docker desktop」と検索し、「開く」を押してください。

この画面が表示されたら起動成功です。

SpringBootでTodo開発:参考画像2

最後に、ubuntu 上で下記コマンドを実行します。

github/ozack-todo-app/todoapp$ docker compose up -d
[+] Running 4/4
 ✔ Network todoapp_default  Created                                                                                0.0s
 ✔ Volume "db_volume"       Created                                                                                0.0s
 ✔ Container mysql          Started                                                                                0.5s
 ✔ Container adminer        Started                  
SpringBootでTodo開発:Docker参考画像2
こんな画面になると思います

実行後は Docker Desktop 上の表示も以下に切り替わります。

SpringBootでTodo開発:参考画像3

これでコンテナの起動が完了しました。

build.gradle を変更

build.gradle を開いてください。

SpringBootでTodo開発:build.gradle 参考画像1

flyway の設定を反映します。

大体はスタートガイドに書いてあることをパクって少し追記するだけです。

// gradle スクリプトを実行するために必要な依存関係を追加
buildscript {
	dependencies {
		// Flyway の MySQL ライブラリをビルドスクリプトに追加
		classpath 'org.flywaydb:flyway-mysql:10.0.0'
	}
}

plugins {
	id 'java'
	id 'org.springframework.boot' version '3.4.1'
	id 'io.spring.dependency-management' version '1.1.7'
	id "org.flywaydb.flyway" version "10.0.0"
}

group = 'com.ozack' // ここはプロジェクト生成時に決めた名前にする
version = '0.0.1-SNAPSHOT'

java {
	toolchain {
		languageVersion = JavaLanguageVersion.of(21)
	}
}

configurations {
	compileOnly {
		extendsFrom annotationProcessor
	}
}

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	implementation 'org.springframework.boot:spring-boot-starter-security'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	implementation 'org.flywaydb:flyway-core'
	implementation 'org.flywaydb:flyway-mysql'
	compileOnly 'org.projectlombok:lombok'
	developmentOnly 'org.springframework.boot:spring-boot-devtools'
	developmentOnly 'org.springframework.boot:spring-boot-docker-compose'
	runtimeOnly 'com.mysql:mysql-connector-j'
	annotationProcessor 'org.projectlombok:lombok'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	testImplementation 'org.springframework.security:spring-security-test'
	testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}

// マイグレーションツールの設定
flyway {
	// データベースへの接続 URL を指定
	url = 'jdbc:mysql://127.0.0.1:3306/tododatabase'

	// データベースに接続するためのユーザー名を指定
	user = 'myuser'

	// データベースに接続するためのパスワードを指定
	password = 'secret'

	// Flywayが適用されるスキーマ(データベース)を指定
	schemas = ['tododatabase']

	// Flywayのクリーンアップ(マイグレーションを全て取り消し、データベースを初期状態に戻す設定)を無効
	cleanDisabled = false
}

tasks.named('test') {
	useJUnitPlatform()
}

// ./gradlew を実行したときに起動するタスクを設定
defaultTasks 'clean', 'build', 'bootRun'

一番最後の行で定義しており、コマンド「./gradlew」を実行したときに作動します。

ビルドファイルの初期化・生成・起動を行うためのコマンドを指定しました。

左側から順番に実行されます。

application.properties を変更

このファイルにも flyway の設定を反映します。

SpringBootでTodo開発:application.properties 参考画像1

下記内容に変更してください。

spring.application.name=todoapp
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/tododatabase?serverTimezone=Asia/Tokyo
spring.datasource.username=myuser
spring.datasource.password=secret
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.flyway.locations=filesystem:src/main/resources/db/migration/table

SQL テーブルを生成

ここから SQL 文をゴリゴリ書きます。

前回作成した以下の ER 図のとおりにテーブルを生成します。

2_userPK`user_id` bigint unsigned NOT NULL AUTO_INCREMENTFK`authority_id` int unsigned NOT NULL `name` varchar(16) NOT NULLUK`email` varchar(32) NOT NULL`password` varchar(32) NOT NULL`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP3_todoPK`todo_id` bigint unsigned NOT NULL AUTO_INCREMENTFK`user_id` bigint unsigned NOT NULLUK`title` varchar(32) NOT NULL`is_check` tinyint(1) NOT NULL`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP1_authorityPK`authority_id` int unsigned NOT NULL AUTO_INCREMENTUK`name` varchar(16) NOT NULL`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP1_cateoryPK`category_id` int unsigned NOT NULL AUTO_INCREMENTUK`name` varchar(16) NOT NULL`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP4_todo_categoryPK`todo_category_id` bigint unsigned NOT NULL AUTO_INCREMENTFK`todo_id` bigint unsigned NOT NULLFK`category_id` int unsigned NOT NULL`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP

SQLファイルの作成

migration フォルダ内に「table」フォルダを作成してください。

そして、table フォルダ内に5つの SQL ファイルを作成します。

SpringBootでTodo開発:SQL参考画像2
tableフォルダ内に SQL ファイルを作成

ファイル名が緑色になっていたり下のブランチ名が変わっていたりしています。

これは、自分が Git でプロジェクトを管理しているからこうなってるだけで、なくても全く問題ないです。

後々で覚えていけばよいと思います。

ファイル数がER図のテーブル数と一致してることが分かると思います。

後ほど、このファイルに SQL 文を記載します。

また、バージョン番号「VX.Y.Z」の X を、ER図のテーブル名にある数字と一致させています。

X が同じ数値のテーブルが複数存在する場合は、Yでアルファベット順に番号を付与します。

要するに、ロードする順番を決めているのです。

ファイル名にバージョン番号を付与する記法は Flyway というライブラリの仕様です。

バージョン番号を基準に昇順で SQL ファイルをロードします。

ロード対象はデフォルトで「migration」配下のファイルとなっていますが、設定で変更可能です。

現に application.properties で変更しています。

なお、 Flyway は環境構築時で既にインストールしています。

一方、Zには1か2の数値を割り当てます。

2を使用するのは少し先になりますが、

  1. テーブル定義ファイル
  2. 本番データ登録ファイル

に場合わけして付与します。

本番環境では1と2、テスト環境では1のみをロードします。

テストの際は各テスト毎に一部のデータしか使用しないので、テストデータが記載された SQL ファイルを全ロードする Flyway の機能自体を適用しません。

詳細はテストコード作成時に説明します。

SQL文の作成

5つの SQL ファイルを完成させます。

-- 権限情報
CREATE TABLE `authority`
(
    `id`         bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '権限ID',
    `name`       varchar(16) NOT NULL COMMENT '権限名',
    `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '作成日時',
    `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新日時',
    PRIMARY KEY (`id`),
    UNIQUE (`name`)
) ENGINE=InnoDB
-- カテゴリー情報
CREATE TABLE `category`
(
    `id`         bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'カテゴリーID',
    `name`       varchar(16) NOT NULL COMMENT 'カテゴリー名',
    `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '作成日時',
    `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新日時',
    PRIMARY KEY (`id`),
    UNIQUE (`name`)
) ENGINE=InnoDB
-- ユーザー情報
CREATE TABLE `user`
(
    `id`           bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'ユーザーID',
    `authority_id` bigint unsigned NOT NULL COMMENT '権限ID',
    `name`         varchar(16) NOT NULL COMMENT 'ユーザー名',
    `email`        varchar(32) NOT NULL COMMENT 'メールアドレス',
    `password`     varchar(32) NOT NULL COMMENT 'パスワード',
    `created_at`   datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '作成日時',
    `updated_at`   datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新日時',
    PRIMARY KEY (`id`),
    FOREIGN KEY (`authority_id`) REFERENCES `authority`(`id`) ON DELETE CASCADE,
    UNIQUE (`email`)
) ENGINE=InnoDB
-- Todo 情報
CREATE TABLE `todo`
(
    `id`         bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'TodoID',
    `user_id`    bigint unsigned NOT NULL COMMENT 'ユーザーID',
    `title`      varchar(32) NOT NULL COMMENT 'やること内容',
    `is_check`   tinyint(1) NOT NULL COMMENT 'チェックの有無を示す真偽値',
    `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '作成日時',
    `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新日時',
    PRIMARY KEY (`id`),
    FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON DELETE CASCADE,
    UNIQUE (`user_id`, `title`)
) ENGINE=InnoDB
-- todo と category のマッピング情報
CREATE TABLE `todo_category`
(
    `id`           bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'マッピングID',
    `todo_id`      bigint unsigned NOT NULL COMMENT 'TodoID',
    `category_id`  bigint unsigned NOT NULL COMMENT 'カテゴリーID',
    `created_at`   datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '作成日時',
    `updated_at`   datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新日時',
    PRIMARY KEY (`id`),
    FOREIGN KEY (`todo_id`) REFERENCES `todo`(`id`) ON DELETE CASCADE,
    FOREIGN KEY (`category_id`) REFERENCES `category`(`id`) ON DELETE CASCADE,
    UNIQUE (`todo_id`, `category_id`)
) ENGINE=InnoDB

外部キーに設定できます。

参照元のデータが削除されたら、参照先のデータも削除するという制約です。

既に無いデータを参照されると困るので、今回は全ての外部キーに設定しました。

ただ、権限等を削除した場合は、その権限を保持するユーザーも全て消えてしまったりするため、とりあえず設定すればいいとは一概にいえません。

その他は以下の ER 図と全く同じ構成です。

2_userPK`user_id` bigint unsigned NOT NULL AUTO_INCREMENTFK`authority_id` int unsigned NOT NULL `name` varchar(16) NOT NULLUK`email` varchar(32) NOT NULL`password` varchar(32) NOT NULL`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP3_todoPK`todo_id` bigint unsigned NOT NULL AUTO_INCREMENTFK`user_id` bigint unsigned NOT NULLUK`title` varchar(32) NOT NULL`is_check` tinyint(1) NOT NULL`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP1_authorityPK`authority_id` int unsigned NOT NULL AUTO_INCREMENTUK`name` varchar(16) NOT NULL`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP1_cateoryPK`category_id` int unsigned NOT NULL AUTO_INCREMENTUK`name` varchar(16) NOT NULL`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP4_todo_categoryPK`todo_category_id` bigint unsigned NOT NULL AUTO_INCREMENTFK`todo_id` bigint unsigned NOT NULLFK`category_id` int unsigned NOT NULL`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP

動作確認

これで MySQL 上にテーブルを生成することができます。

確認するために、ubuntu 上で下記コマンドを実行してください。

./gradlew

Spring Boot の起動が開始されます。

SpringBootでTodo開発:SpringBoot起動時の画面
SpringBoot 起動時の画面

起動後に Docker Desktop を開いて下線をクリックしてください。

SpringBootでTodo開発:Docker 参考画像3

Adminer のログイン画面に遷移します。

build.gradle 内の flyway 定義で記載した情報を入力してください。

パスワードは「secret」です。

SpringBootでTodo開発:Adminerのログイン画面
Adminerのログイン画面

ログインするとテーブル一覧ページに遷移します。

先ほど作成した5つのテーブルが登録されています。

「flyway_schema_history」はデフォルトで勝手に登録されます。

SpringBootでTodo開発:Adminerのテーブルビュー
Adminerのテーブルビュー

テーブル名をクリックすると詳細情報を確認できます。

SpringBootでTodo開発:Adminerのテーブル詳細
Adminerのテーブル詳細

各キーの設定状況や依存関係も把握可能です。

MySQL 上にテーブルを生成することができました👍

エラーの確認方法

ちなみに、エラーメッセージは下記ファイルに記載されます。

build/reports/tests/test/index.html
SpringBootでTodo開発:index.html 参考画像1
build ディレクトリ配下にある index.html

このHTMLファイルを、ブラウザ上で開くことでエラー詳細を確認できます。

SpringBootでTodo開発:エラー参考画像1
エラー内容の詳細

今回は、テーブル定義の変更内容が Flyway に反映されていないエラーです。

下記コマンドを入力して対応します。

github/ozack-todo-app/todoapp$ ./gradlew flywayClean
SpringBootでTodo開発:Gradle参考画像1
実行後の画面

一見、どこにもエラー内容が出力されていないので戸惑うと思います。

コマンド上ではなくHTMLファイルに出力されるので、覚えておきましょう。

プログラミング時にはロガーをインポートできるので大した問題ではないです。

エラーが出力されない問題は主に環境構築の段階で発生します。

まとめ

今回は、事前に定義した ER 図を用いて SQL テーブルを生成しました。

src

  1. compose.yaml
  2. build.gradle

src/main/…/resources

  1. application.properties

src/main/…/resources/…/table

  1. フォルダ内の全ファイル

プロジェクト構成は GitHub にプッシュしています。

GitHub - o-zack-0390/SpringBootTodoServer: Todo データを処理するSpringプロジェクト
Todo データを処理するSpringプロジェクト. Contribute to o-zack-0390/SpringBootTodoServer development by creating an...

これでデータベース関連の準備が完了したので、Spring Boot 側の開発に移れます。

なのですが、Spring Boot は基本的な開発スタイルを知っていないと全く分からなかったりするので、次回は SpringBoot での開発方法を説明します。

タイトルとURLをコピーしました