SpringBootでDBのマイグレーションを管理する(MySQL)

前回のつづき
前回はDockerを使用してMySQLコンテナ起動を行った。

[SpringBoot 向けのMySQLセットアップ覚え書き](https://qiita.com/dorayakin/items/110ac080321bf010c58d)

## 目的
SpringBootアプリケーションとMySQLの接続設定をする。
migrationファイルを作成してDBの変更管理を可能にする。

## 環境
(前回と同じ)
WSL バージョン: 2.3.26.0
カーネル バージョン: 5.15.167.4-1
WSLg バージョン: 1.0.65
MSRDC バージョン: 1.2.5620
Direct3D バージョン: 1.611.1-81528511
DXCore バージョン: 10.0.26100.1-240331-1435.ge-release
Windows バージョン: 10.0.22631.4460
Rancher Desktop V1.16.0
MySQL 8.0

SpringBoot 3.3.5

:::note warn
VSCodeで開発を行う場合はSTSの拡張も要導入
https://spring.io/tools
:::
## POMファイルの依存ライブラリを設定
dependenciesとpluginsに必要なライブラリとプラグインを追加
```xml
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
		</dependency>
		<dependency>
			<groupId>org.apache.maven.plugins</groupId>
			<artifactId>maven-compiler-plugin</artifactId>
			<version>3.13.0</version>
		</dependency>
		<dependency>
			<groupId>org.flywaydb</groupId>
			<artifactId>flyway-core</artifactId>
		</dependency>
		<dependency>
			<groupId>org.flywaydb</groupId>
			<artifactId>flyway-mysql</artifactId>
		</dependency>
		<dependency>
			<groupId>com.mysql</groupId>
			<artifactId>mysql-connector-j</artifactId>
		</dependency>
	</dependencies>
	<build>
		<plugins>
			<plugin>
				<groupId>org.flywaydb</groupId>
				<artifactId>flyway-maven-plugin</artifactId>
			</plugin>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
 
```

 ## ~~application.properties~~  →application.yml
 application.propertiesでSpringBootとMySQLの接続設定を行う。
 次のパスに格納されている。
`demo\src\main\resources\application.properties`
特に編集していなければまだ次の一行しか記載されていない。
```properties
spring.application.name=demo
```

`application.properties`のままだと扱いづらいためpropertyファイルの形式をymlに変える。
ファイル名は`application.yml`
```yml
spring:
  application:
    name: demo

```

:::note info
VSCodeでSTSの拡張を導入している場合、`application.properties`を右クリックするとyamlに変換する項目が表示される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/310625/24bf07cc-c781-367d-0795-6acd11870352.png)

:::

MySQLへの接続設定とflywayの設定を追加する。
datasourceでは接続するDBとドライバを設定。
flywayのlocationsのフォルダにmigrationファイルを格納する。
serverの項目はアプリケーションのポートを指定している。

```yaml
spring:
  application:
    name: demo
    #Spring Datasource (MySQL access info)
  datasource:
    url: jdbc:mysql://localhost:3306/mydatabase
    username: AAAA
    password: BBBB
    driver-class-name: com.mysql.cj.jdbc.Driver
    #Flyway settings
  flyway:
    locations: classpath:db/migration
    user: AAAA
    password: BBBB
    url: jdbc:mysql://localhost:3306/mydatabase
server:
  port: 3000
```
:::note info
詳しくないうちはapplication.ymlはgitignoreファイルで追跡対象外にしてgit管理をしないことを推奨。
:::
## migrationファイルの作成
`demo\src\main\resources`に`db\migration`のフォルダを作成する。
ここにmigrationファイルを格納する。
migrationファイルはファイル名に注意が必要。
今回はファイル名を`V0.01__Create_city_table.sql`とする。
マイグレーションファイル名は`V<VERSION>__<NAME>.sql`の形式で作成する必要がある。
```sql
--  V0.01__Create_cities_table.sql
CREATE TABLE city( 
    id BIGINT AUTO_INCREMENT PRIMARY KEY, 
    prefecture_id CHAR (2) NOT NULL, 
    code CHAR (3) NOT NULL, 
    name VARCHAR (10) NOT NULL, 
    name_kana VARCHAR (20) NOT NULL,
    kana_initial VARCHAR (20) NOT NULL
);
```


## migration実行


アプリケーション起動時に次のようなログが表示されればmigration実行成功。

```
2024-12-09T19:40:13.272+09:00  INFO 29004 --- [demo] [           main] org.flywaydb.core.FlywayExecutor         : Database: jdbc:mysql://localhost:3306/mydatabase (MySQL 8.0)
2024-12-09T19:40:13.333+09:00  INFO 29004 --- [demo] [           main] o.f.core.internal.command.DbValidate     : Successfully validated 1 migration (execution time 00:00.019s)
2024-12-09T19:40:13.346+09:00  INFO 29004 --- [demo] [           main] o.f.core.internal.command.DbMigrate      : Current version of schema `mydatabase`: << Empty Schema >>
2024-12-09T19:40:13.355+09:00  INFO 29004 --- [demo] [           main] o.f.core.internal.command.DbMigrate      : Migrating schema `mydatabase` to version "0.01 - Create city table"
2024-12-09T19:40:13.403+09:00  INFO 29004 --- [demo] [           main] o.f.core.internal.command.DbMigrate      : Successfully applied 1 migration to schema `mydatabase`, now at version v0.01 (execution time 00:00.023s)
```
:::note info
VSCodeでのアプリケーション起動方法
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/310625/11c7dcc6-0cce-51e8-1c50-9a04dd8ac19d.png)
画面左端のアイコンのSpringBootDashboardを選択するとアプリケーション名が表示される。
起動したいアプリケーションにカーソルを合わせると▷のマークが表示され、クリックするとアプリケーションを起動できる。
:::

## エラーメッセージ:Communications link failure
`docker compose up -d`でコンテナを起動後、アプリケーションを起動すると次のようなエラーメッセージが表示される場合がある。
```
The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL State  : 08S01
Error Code : 0
Message    : Communications link failure

The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
```
`docker compose up -d`はバックグラウンドでコンテナ起動をするコマンドである。
このメッセージが表示されている原因の一つとしてコンテナの起動が完了していない状態でアプリケーションを起動すると表示される場合がある。
しばらく待って再度アプリケーション起動を行ってみてください。

## 補足:コンテナ内部でコマンドを実行したい、直接SQLを実行したいとき…
1. コンテナ内に入る。
`docker compose up -d`を実行したあとそのままコンソールで次のコマンドを入力する。
今回はサービス名にdbとつけているので
`docker compose exec db bash`となる。
2. コンテナでMySQLクライアントを立ち上げる。
`myuser`と`mydatabase`はenvファイルに記載したMySQLのユーザー名とデータベース名を入力する。
`mysql -u demouser demodatabase -p`
この後パスワードの入力が求められるのでそのままenvファイルに記載したMySQLのユーザーのパスワードを入力する。


## 参考
https://docs.spring.io/spring-boot/how-to/data-initialization.html#howto.data-initialization.migration-tool.flyway