flywayでMySQLのテーブルを管理する（入門）

# 概要

- MySQLのDDLの管理がしたくなったのでflywayを使ってみる
- 一応現場でも使用することを想定してパスワードの直打ちやファイルに記載してGitに上がってしまうことがないように意識してみています
- flywayコマンドの実行結果は可視性の向上のために説明に必要な部分のみ記載します

# 環境やバージョン

- windows
- MySQL 5.7　（ローカル）
- flyway 4.2.0

# 参考

- https://flywaydb.org/

# Flywayのインストール

まずはflywayのインストールから  
[ここ](https://flywaydb.org/documentation/commandline/)からZipファイルを取得し、解凍。  
今回は１から必要なファイル等を把握していきたいので
`flyway-<version>`配下の「flyway」と「flyway.cmd」のみをPathの通ったディレクトリに配置する

```
<PATH>
 └ flyway
 └ flyway.cmd
```

# MySQLの構築


## ダウンロード
- [ここ](https://dev.mysql.com/downloads/installer/)からダウンロード
- 上のweb版の方をダウンロードしましたが特にやりにくい感じではなくインストールを進められました

## 接続

インストール時に設定したパスワードを用いて接続します

```sh
>mysql -u root -p
Enter password: *****
```

## データベースの作成

Flywayでは接続情報としてDBまでは必要になるため、
事前に作成しておきます

```sql
create database sample;
```


> この記事では実施をしませんが、実際に運用する際は必要な権限のみを持ったユーザーを作成してrootユーザーでflywayを実行することはしないなと思います。

# Flywayの設定～疎通確認

任意のディレクトリで設定ファイルを作成していきます

```conf/flyway.conf
flyway.url=jdbc:mysql://localhost:3306/sample
flyway.user=root
#flyway.password=

flyway.locations=filesystem:sql/
```

パスワードは以下のようにユーザー入力によって設定します

```sh:windows
>set /P FLYWAY_PASSWORD="flyway.password: "
flyway.password: *****
```

```bash:mac
$ echo -n "flyway.password: "; read FLYWAY_PASSWORD
flyway.password: *****
```

ここまでできたら疎通確認をしてみます

```sh
>flyway -configFile=conf\flyway.config -password=%FLYWAY_PASSWORD% info

+---------+-------------+---------------------+---------+
| Version | Description | Installed on        | State   |
+---------+-------------+---------------------+---------+
| No migrations found                                   |
+---------+-------------+---------------------+---------+
```

macの場合は変数の読込が`${FLYWAY_PASSWORD}`となるはずです。

> [ドキュメント](https://flywaydb.org/documentation/envvars)を見る限り、環境変数に設定するだけで使用可能なように見えるのですが、うまくできなかったので実行時引数で渡していますmm

# Flywayの使い方

## SQL作成

ここからSQLを書いていきます。

SQLファイルは形式が決まっており`V<version>__<description>.sql`という形式で作成します。

今回はversion=1.0.0で作成してみます 
`1`, `1.0`といったバージョンも可です

> あくまで参考に…ですが、僕だったらこのように使い分けます
major version: ユーザー追加等のDB管理に関する変更時
minor version: テーブルやインデックスの追加・更新等の通常変更時
patch version: minor versionを上げたあとの軽微な修正

```sql:V1.0.0__create_sample_table.sql
create table sample (
  id varchar(10) primary key,
  name varchar(10)
);
```

## 状態確認

疎通確認時のコマンドと一緒です 
infoコマンドを使用します

```sh
>flyway -configFile=conf\flyway.config -password=%FLYWAY_PASSWORD% info

+---------+---------------------+---------------------+---------+
| Version | Description         | Installed on        | State   |
+---------+---------------------+---------------------+---------+
| 1.0.0   | create sample table |                     | Pending |
+---------+---------------------+---------------------+---------+
```

ファイル名からVersionとDescriptionが抽出され、Statusには現在のSQLの実行状態が表示されます。

SQL実行前は「Pending」となっています。

## 反映

migrateコマンドを使用します

```sh
>flyway -configFile=conf\flyway.config -password=%FLYWAY_PASSWORD% migrate

Migrating schema `sample` to version 1.0.0 - create sample table
Successfully applied 1 migration to schema `sample` (execution time 00:00.118s).

>flyway -configFile=conf\flyway.config -password=%FLYWAY_PASSWORD% info

+---------+---------------------+---------------------+---------+
| Version | Description         | Installed on        | State   |
+---------+---------------------+---------------------+---------+
| 1.0.0   | create sample table | 2020-09-02 21:27:34 | Success |
+---------+---------------------+---------------------+---------+
```

正常にSQLが実行できるとStateが「Success」となります！

## ベースラインの設定

例えば、途中までは手動でSQLを実行していたけれども、これからはFlywayでSQL管理したいといったケースを考えてみます。

```
sql
 └ V1.0.0__create_sample_table.sql  ←　手動で実行していたSQL
 └ V2.0.0__add_column_to_sample_table.sql  ←　このSQLからFlywayで管理したい
```

V1.0.0のSQLがすでにflyway以外の方法で実行されていた場合、各コマンドは以下のような結果になります。

```sh
>flyway -configFile=conf\flyway.config -password=%FLYWAY_PASSWORD% info

+---------+----------------------------+---------------------+---------+
| Version | Description                | Installed on        | State   |
+---------+----------------------------+---------------------+---------+
| 1.0.0   | create sample table        |                     | Pending |
| 2.0.0   | add column to sample table |                     | Pending |
+---------+----------------------------+---------------------+---------+

>flyway -configFile=conf\flyway.config -password=%FLYWAY_PASSWORD% migrate

ERROR: Found non-empty schema(s) `sample` without metadata table! Use baseline() or set baselineOnMigrate to true to initialize the metadata table.
```

baselineを使ってねと出力されているので、baselineを設定してみます。 
`baseline`コマンドと`baselineVersion`オプションを使用します

```sh
>flyway -configFile=conf\flyway.config -password=%FLYWAY_PASSWORD% -baselineVersion=1.0.0 baseline

Creating Metadata table: `sample`.`schema_version`
Successfully baselined schema with version: 1.0.0

>flyway -configFile=conf\flyway.config -password=%FLYWAY_PASSWORD% info

+---------+----------------------------+---------------------+---------+
| Version | Description                | Installed on        | State   |
+---------+----------------------------+---------------------+---------+
| 1.0.0   | << Flyway Baseline >>      | 2020-09-02 22:37:49 | Success |
| 2.0.0   | add column to sample table |                     | Pending |
+---------+----------------------------+---------------------+---------+
```

すると、1.0.0がSuccessとなり、migrateも通るようになります！

```sh
>flyway -configFile=conf\flyway.config -password=%FLYWAY_PASSWORD% migrate

Migrating schema `sample` to version 2.0.0 - add column to sample table
Successfully applied 1 migration to schema `sample` (execution time 00:00.060s).

>flyway -configFile=conf\flyway.config -password=%FLYWAY_PASSWORD% info

+---------+----------------------------+---------------------+---------+
| Version | Description                | Installed on        | State   |
+---------+----------------------------+---------------------+---------+
| 1.0.0   | << Flyway Baseline >>      | 2020-09-02 22:37:49 | Success |
| 2.0.0   | add column to sample table | 2020-09-02 22:40:32 | Success |
+---------+----------------------------+---------------------+---------+
```

## migrateに失敗したとき

例えばSQLの構文エラーがあったりすると以下のようにStateが`Failed`になる

```
>flyway -configFile=conf\flyway.config -password=%FLYWAY_PASSWORD% info

+---------+---------------------+---------------------+---------+
| Version | Description         | Installed on        | State   |
+---------+---------------------+---------------------+---------+
| 1.0.0   | create sample table | 2020-09-02 23:03:19 | Failed  |
+---------+---------------------+---------------------+---------+
```

このようなときはSQLを修正し、`repair`コマンドを実行し、migrate前の状態に復元。 
その後再度`migrate`コマンドを実行する。

```bash
>flyway -configFile=conf\flyway.config -password=%FLYWAY_PASSWORD% repair

Successfully repaired metadata table `sample`.`schema_version` (execution time 00:00.032s).
Manual cleanup of the remaining effects the failed migration may still be required.

>flyway -configFile=conf\flyway.config -password=%FLYWAY_PASSWORD% info

+---------+---------------------+---------------------+---------+
| Version | Description         | Installed on        | State   |
+---------+---------------------+---------------------+---------+
| 1.0.0   | create sample table |                     | Pending |
+---------+---------------------+---------------------+---------+

>flyway -configFile=conf\flyway.config -password=%FLYWAY_PASSWORD% migrate

Migrating schema `sample` to version 1.0.0 - create sample table
Successfully applied 1 migration to schema `sample` (execution time 00:00.044s).

>flyway -configFile=conf\flyway.config -password=%FLYWAY_PASSWORD% info

+---------+---------------------+---------------------+---------+
| Version | Description         | Installed on        | State   |
+---------+---------------------+---------------------+---------+
| 1.0.0   | create sample table | 2020-09-02 23:17:02 | Success |
+---------+---------------------+---------------------+---------+
```

### 補足：repairコマンドの動作

repairコマンドで実行されるのは、version管理用のテーブルにおいて、Stateが「Failed」のものを「Pending」に戻すだけです。
そのため、以下のようなSQLファイルを実行し、２つめのSQLで失敗した場合は1つ目のSQLの結果を手動で戻してあげる必要があります

```sql:sample.sql
create table sample1 (
  hoge varchar(10) primary key
);

create table sample2 (
  hoge text primary key
);
```

この場合だと`drop table sample1;`を手動実行してあげるが必要あります。
ちなみにFlywayのmetadataは「schema_version」という自動で作成されるテーブルで管理されています。