FlywayでDBバージョン管理をする

# 概要
会社で、SpringBootからFlywayを使ってDBのバージョン管理をしています。
導入してから細かい部分を確認した結果をまとめました。

## Flyway とは
データベース定義をバージョン管理できるツールです
基本的にはJava環境で動きますが、Javaがなくてもコマンドラインツールとして使うこともできます

https://flywaydb.org/

仕組みは公式サイトのここに書いてあります
https://flywaydb.org/documentation/getstarted/how

# 挙動の確認
以下の環境で確認しました
- MySQL
- Spring Boot
  - Java 11
  - Gralde
  - Flyway 7.7.3

## コマンド
`./gradlew flywayBaseline`
DB に flyway_schema_history テーブルが作られて、BASELINE のデータ1件が登録されます。
build.gradle の baselineVersion が flyway_schema_history の BASELINE と不一致だとFAILEDになります。

`./gradlew flywayValidate`
「flyway_schema_history」と「定義ファイル」を比較して、`type`と`checksum`が不一致だとFAILEDになります。

「build.gradle の target」と「Schema version」が不一致でもFAILEDになります。
ex) 定義をSQLファイルにしている場合、ファイルの内容が同じでもファイル名を変更したり、改行やコメントを追加したりすると、不一致でFAILEDになります。

`./gradlew flywayMigrate`
State = Pending のバージョンのSQLを実行します。

`./gradlew flywayInfo`
その時の情報(バージョンごとの反映状況)を出力します。

`./gradlew flywayRepair`
SQLのシンタックス等のミスでfailedになったバージョンのSQLを履歴から削除します(State: Failed -> Pending)。
履歴削除後に`flywayMigrate`すれば、またSQL実行して履歴登録されます。

## バージョン番号のつけ方
https://flywaydb.org/documentation/concepts/migrations.html#naming

build.gradle では `target = '6.0.0.1'` のようにシングルクォーテーションでくくると小数も使えます。
このバージョン番号だと、ファイル名は V6_0_0_1__create_table.sql のようになります。
反映済みバージョンより大きい値にします(間の値にするとmigrateが失敗します)。

# SpringBoot + Gradle での設定方法
Springの"How-to" Guidesに「Execute Flyway Database Migrations on Startup」に説明があります
https://docs.spring.io/spring-boot/docs/current/reference/html/howto.html#howto.data-initialization.migration-tool.flyway

## SpringBoot起動時にFlywayのDBマイグレーションを実行させる
(1) flyway-coreをクラスパスに追加する
```build.gradle
dependencies {
    implementation "org.flywaydb:flyway-core"
}
```

(2) `spring.flyway.locations`で指定したフォルダにマイグレーション用ファイルを配置する
`spring.flyway.locations`はデフォルトだと`classpath:db/migration`です

## ベースラインを途中から始める
途中からFlywayを導入する場合は、実行済みファイル以降のバージョンを指定します
指定したバージョン以降がFlywayの処理対象になります
```application-[env].yml
spring:
  flyway:
    baseline-version: 2
```

## 環境別設定
flyway実行をさせない
```application-[env].yml
spring:
  flyway:
    enabled: false
```

データ投入など別ファイルも実行させるには、locationsに別フォルダも指定すればOK
```application-[env].yml
spring:
  flyway:
    locations: "classpath:db/migration,classpath:db/mock-data"
```


# 用語まとめ
## ベースライン
- flywayで管理しはじめるバージョン、これより前のバージョン(Below Baseline)はflyway管理対象外となる
- build.gradle の flyway.baselineVersion で指定する
- ベースラインバージョンの確認方法
  - flyway_schema_history で type = BASELINE の バージョン
  - flywayInfo で State = Baseline のバージョン

## migrate
- migrateすると、flywayとしてバージョン管理されるようになる
- migrate済みの確認方法
  - flyway_schema_history で success = 1 になっている
  - flywayInfo で State = Success になっている

## flywayInfo の State
- `Pending`: migrate待ち
- `Success`: migrate済み
- `Ignored`: バージョン番号がBaselineより大きいけど、Schema versionより小さいとき無視される(migrateしない)
  - バージョンのつけ方がおかしいとIgnoredになるので、バージョンがちゃんと順番になっていることを確認する
  - flyway_schema_historyには登録されていないはず
- `Above Target`: migrate対象より大きいバージョン(まだmigrateしない)
  - migrateを進めてPendingがなくなったら順番にPendingになる
- `Baseline`: ベースライン(migrateしない)
- `Below Baseline`: ベースラインより前(migrateしない、historyテーブルに登録されない)
- `Failed`: migrate失敗

一覧はこちら
~~https://documentation.red-gate.com/fd/migrations-184127470.html#Migrations-MigrationStates~~
https://documentation.red-gate.com/fd/flyway-schema-history-table-273973417.html

### 例
- Baseline = 3
- ファイル
  - V1__create_table_a.sql
  - V2__create_table_b.sql
  - V3__create_table_c.sql
  - V4__create_table_d.sql

```flywayInfo.log
Schema version: 4
+-----------+---------+------------------------------------+----------+---------------------+----------------+
| Category  | Version | Description                        | Type     | Installed On        | State          |
+-----------+---------+------------------------------------+----------+---------------------+----------------+
| Versioned | 1       | create table a                     | SQL      |                     | Below Baseline |
| Versioned | 2       | create table b                     | SQL      |                     | Below Baseline |
|           | 3       | << Flyway Baseline >>              | BASELINE | 202X-XX-XX 12:34:56 | Baseline       |
| Versioned | 4       | create table d                     | SQL      | 202X-XX-XX 12:34:56 | Success        |
+-----------+---------+------------------------------------+----------+---------------------+----------------+
```

```flyway_schema_history.log
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|installed_rank | version | description            | type     | script                 | checksum   | installed_by | installed_on        | execution_time | success |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|1              | 3       | << Flyway Baseline >>  | BASELINE | << Flyway Baseline >>  | « NULL »   | root         | 202X-XX-XX 12:34:56 | 0              | 1       |
|2              | 4       | create table d         | SQL      | V4__create_table_d.sql | 1661414772 | root         | 202X-XX-XX 12:34:56 | XX             | 1       |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------
```