Flyway 4.2の仕組み、使い方を学ぶ

# 概要

FlywayはJVM上で動作するデータベースのマイグレーションツールです。
Flywayの使い方にはいくつか（コマンドラインツール、Mavenプラグイン、Gradleプラグインなど）ありますが、この記事ではコマンドラインツールとして使う方法を学んだ結果をまとめました。

**環境**

* Windows 10 Professional
* Flyway 4.2.0
* MySQL 5.7.19

**参考**

* [Documentation - Flyway] (https://flywaydb.org/documentation/)

# 仕組み

## バージョン管理

Flywayでは管理対象のスキーマのバージョンを下記の情報から管理しています。

1. ベースラインのバージョン
2. 管理対象のスキーマに適用する変更内容を持つマイグレーションファイルのバージョン
    3. バージョンを持たないリピータブルマイグレーションファイルというのもあります
3. その適用結果を格納するschema_versionという名前のメタデータテーブル

たとえば下記のinfoコマンドの結果でいえば

* (1)がベースラインのバージョンです。
* (2)が適用したマイグレーションファイルのバージョンです。
* (3)が未適用のマイグレーションファイルのバージョンです。

```bat
> flyway.cmd info
Flyway 4.2.0 by Boxfuse

Database: jdbc:mysql://localhost:3306/flyway_demo_db (MySQL 5.7)

+---------+-------------------------------+---------------------+---------+
| Version | Description                   | Installed on        | State   |
+---------+-------------------------------+---------------------+---------+
| 1.0.0   | App version 1.0               | 2017-12-04 20:24:51 | Baselin | <--- (1)
| 1.1.0   | create table demo a           | 2017-12-04 20:40:01 | Success | <--- (2)
| 1.1.1   | insert data demo a            | 2017-12-04 20:40:01 | Success | <--- (2)
| 1.2.0   | create table demo b           |                     | Pending | <--- (3)
| 1.2.1   | insert data demo b someting a |                     | Pending | <--- (3)
| 1.2.2   | insert data demo b someting b |                     | Pending | <--- (3)
+---------+-------------------------------+---------------------+---------+
```

となります。

適用済みか未適用かはState欄で判断できます。StateがPendingなのはマイグレーションファイルがスキーマに反映されていないバージョンという意味になります。

### ベースライン

Flywayでバージョン管理を行うには最初にbaselineコマンドでベースラインのバージョンを指定する必要があります。
baselineコマンドを実行するとバージョンを保持するschema_versionというメタデータテーブルが管理対象のスキーマに作成され、指定したベースラインのバージョンが登録されます。（指定しなかった場合のデフォルトは1）
ベースラインのバージョンは、適用するマイグレーションファイルのバージョンの下限になります。ベースラインのバージョンより古いマイグレーションファイルは認識はされますがmigrateコマンドの適用範囲外になります。

### マイグレーションファイル

マイグレーションファイルとは、管理対象のスキーマに適用する変更内容を記述したSQLファイルです。
ファイル名には命名ルールがあり、バージョン`{version}`と説明`{description}`を付加します。
バージョンは一意でなければならず、同じバージョンを持つマイグレーションファイルを作成することはできません。

**デフォルトのルール**

半角大文字のVから始まり`{version}`と`{description}`の間には2つの半角アンダースコア(セパレータ)が必要です。

```text
V{version}__{description}.sql
```

**例**

```text
V1_0_0__somethings_name.sql
```

ルールはconfファイルでカスタマイズすることができます。

```text
# File name prefix for sql migrations (default: V )
# flyway.sqlMigrationPrefix=
# File name separator for Sql migrations (default: __)
# flyway.sqlMigrationSeparator=
# File name suffix for Sql migrations (default: .sql)
# flyway.sqlMigrationSuffix=
```

### リピータブルマイグレーションファイル

ビュー、プロシージャ、ファンクションなどのオブジェクトのマイグレーションを行いたい場合に使用します。
ビュー、プロシージャ、ファンクションなどは変更内容を差分のファイルとして表現できないので常に同じファイルで管理します。このためファイルにはバージョン`{version}`を持ちません。

たとえばビューを作成するファイルを、バージョンを持つマイグレーションファイルで管理しようとした場合、変更が発生するたびに新しいバージョンを持つSQLファイルで作り直していくことになり、内容の似たSQLファイルを量産してしまうことになります。

**デフォルトのルール**

半角大文字のRと2つの半角アンダースコア(セパレータ)から始まり次に`{description}`が必要です。
バージョン管理はしないので`{version}`はつけません。

```text
R__{description}.sql
```

**例**

```text
R__create_view_demo_v.sql
```

ルールはconfファイルでカスタマイズすることができます。

```text
# File name prefix for repeatable sql migrations (default: R )
# flyway.repeatableSqlMigrationPrefix=
```

### schema_versionテーブル

このメタデータテーブルはFlywayのbaselineコマンド実行時に自動的に作成され、migrateコマンドの実行結果を格納します。

このテーブル名はconfファイルでカスタマイズすることが可能です。

```text
# Name of Flyway's metadata table (default: schema_version)
# flyway.table=
```

# 動作確認用データベース

flywayの動作確認で使用するデータベースの環境です。

**データベース**

```sql
CREATE DATABASE IF NOT EXISTS flyway_demo_db
  CHARACTER SET = utf8mb4
  COLLATE = utf8mb4_general_ci;
```

**アカウント,権限**

```sql
CREATE USER IF NOT EXISTS 'demo_user'@'localhost'
  IDENTIFIED BY 'demo_pass'
  PASSWORD EXPIRE NEVER;
```

```sql
GRANT ALL ON flyway_demo_db.* TO 'demo_user'@'localhost';
```

# コマンドラインツールとして使う

https://flywaydb.org/documentation/commandline/

## インストール

Windows版のアーカイブファイルをダウンロードして適当な場所へ展開します。

**バージョン確認**

```text
> flyway.cmd -v
Flyway 4.2.0 by Boxfuse
```

**Usage**

```text
> flyway [options] command
```

## デフォルトのディレクトリ構成

```text
[Flyway_home]
  ├─conf
  │  └─ flyway.conf  // confファイル
  ├─drivers          // 各種DBのJDBCドライバの配置場所
  ├─jars
  ├─jre              // Java Runtime
  ├─lib
  │  ├─ flyway-commandline-4.2.0.jar
  │  └─ flyway-core-4.2.0.jar
  ├─sql              // マイグレーションSQLファイルの配置場所
  ├─flyway           // bash用
  └─flyway.cmd       // CMD用実行ファイル
```

### 設定ファイル

confディレクトリにあるflyway.confで設定を行います。
設定項目はたくさんありますが、この記事ではデータベース接続に関係する部分のみ設定しそれ以外はデフォルトのままとしました。

```text
# Jdbc url to use to connect to the database
flyway.url=jdbc:mysql://localhost:3306/flyway_demo_db
# User to use to connect to the database. Flyway will prompt you to enter it if not specified.
flyway.user=demo_user
# Password to use to connect to the database. Flyway will prompt you to enter it if not specified.
flyway.password=demo_pass
```

なお、confファイルで設定可能な項目はflywayコマンドの実行時のオプションで上書き可能です。
たとえばパスワードはconfで管理したくないといった場合は、下記のようにオプションで指定できます。

```bat
> flyway.cmd info -password=demo_pass
```

#### プレースホルダの定義

confファイルに任意のプレースホルダを定義することができます。定義したプレースホルダはマイグレーションファイルから利用することができます。

**例**

```text
flyway.placeholders.testTargetDate=2017-12-01
```

プレースホルダの値を参照するには`${placeholer_name}`と記述します。

```sql
UPDATE sometable
   SET some_flag = 0
 WHERE created_at >= '${testTargetDate}';
```

### マイグレーションファイル

sqlディレクトリ下にマイグレーションファイルを配置します。ここに命名ルールに従っているsqlファイルを配置すればFlywayから認識されます。

マイグレーションファイルの配置場所はconfファイルでカスタマイズすることが可能です。

```text
# Comma-separated list of locations to scan recursively for migrations. (default: filesystem:<<INSTALL-DIR>>/sql)
# flyway.locations=
```

# コマンドの使い方

## 1.コマンドの種類

コマンドの種類は下表のとおりです。詳しくはFlywayのhelpでコマンド、オプションを確認することができます。

|command  |description              |
|:--------|:------------------------|
|migrate  |Migrates the database    |
|clean    |Drops all objects in the configured schemas|
|info     |Prints the information about applied, current and |pending migrations|
|validate |Validates the applied migrations against the ones on the classpath|
|baseline |Baselines an existing database at the baselineVersion|
|repair   |Repairs the metadata table|

## 2.未管理の状態

下記は、まだ一度もbaselineコマンドを実行していないときのinfoコマンドの結果です。（baselineコマンドを実行していないとschema_versionテーブルは作成されませんが、infoコマンドの実行は可能です）

```bat
> flyway.cmd info
Flyway 4.2.0 by Boxfuse

Database: jdbc:mysql://localhost:3306/sample_db (MySQL 5.7)

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

## 3.ベースラインのバージョンを設定

このスキーマでは未だバージョン管理を行っていないので、最初にbaselineコマンドでベースラインのバージョンを設定します。

下記の例は、baselineコマンドのオプション`baselineVersion`でベースラインのバージョン、`baselineDescription`で説明文を指定しています。

```bat
> flyway.cmd baseline -baselineVersion=1.0.0 -baselineDescription="App version 1.0"
Flyway 4.2.0 by Boxfuse

Database: jdbc:mysql://localhost:3306/flyway_demo_db (MySQL 5.7)
Creating Metadata table: `flyway_demo_db`.`schema_version`
Successfully baselined schema with version: 1.0.0
```

ベースラインの設定を行うと、infoコマンドでベースラインのバージョンが確認できます。

```bat
> flyway.cmd info
Flyway 4.2.0 by Boxfuse

Database: jdbc:mysql://localhost:3306/flyway_demo_db (MySQL 5.7)

+---------+-----------------+---------------------+---------+
| Version | Description     | Installed on        | State   |
+---------+-----------------+---------------------+---------+
| 1.0.0   | App version 1.0 | 2017-12-05 21:54:54 | Baselin |
+---------+-----------------+---------------------+---------+
```

## 4.マイグレーションの実行

マイグレーションファイルをsqlディレクトリ下に配置することでFlywayから自動的に認識されます。
migrateコマンドの対象となるのはベースラインのバージョンより新しいバージョンでステータスがPendingのものです。

以下のsqlファイルをsqlディレクトリに配置します。

**demo_aテーブルを作成する**

ファイル名：`V1_1_0__create_table_demo_a.sql`

```sql
CREATE TABLE IF NOT EXISTS demo_a (
  id BIGINT NOT NULL AUTO_INCREMENT,
  name VARCHAR(255) NOT NULL,
  PRIMARY KEY (id)
);
```

**demo_aテーブルの初期データを登録する**

ファイル名：`V1_1_1__insert_data_demo_a.sql`

```sql
INSERT INTO demo_a (name) VALUES ('demo a test data 1');
INSERT INTO demo_a (name) VALUES ('demo a test data 2');
INSERT INTO demo_a (name) VALUES ('demo a test data 3');
```

この状態でinfoコマンドを実行すると、sqlディレクトリ下に置いた2つのマイグレーションファイルとそのバージョンが認識されていることがわかります。
ただし、このバージョンはschema_versionテーブルにはまだ登録されていない状態で、migrateコマンドを実行することでデータが登録されます。（マイグレーションの成功時はSuccess、失敗時はFailedとなります）

```bat
> flyway.cmd info
Flyway 4.2.0 by Boxfuse

Database: jdbc:mysql://localhost:3306/flyway_demo_db (MySQL 5.7)

+---------+---------------------+---------------------+---------+
| Version | Description         | Installed on        | State   |
+---------+---------------------+---------------------+---------+
| 1.0.0   | App version 1.0     | 2017-12-05 21:54:54 | Baselin |
| 1.1.0   | create table demo a |                     | Pending |  <--- 認識される
| 1.1.1   | insert data demo a  |                     | Pending |  <--- 認識される
+---------+---------------------+---------------------+---------+
```

migrateコマンドを実行するとマイグレーションファイルが適用され、管理対象のスキーマにテーブルとデータが作成されます。

```bat
> flyway.cmd migrate
Flyway 4.2.0 by Boxfuse

Database: jdbc:mysql://localhost:3306/flyway_demo_db (MySQL 5.7)
Successfully validated 3 migrations (execution time 00:00.017s)
Current version of schema `flyway_demo_db`: 1.0.0
Migrating schema `flyway_demo_db` to version 1.1.0 - create table demo a
Migrating schema `flyway_demo_db` to version 1.1.1 - insert data demo a
Successfully applied 2 migrations to schema `flyway_demo_db` (execution time 00:00.265s).
```

実行結果を確認すると、ステータスがPendingからSuccessに更新されていることがわかります。

```bat
> flyway.cmd info
Flyway 4.2.0 by Boxfuse

Database: jdbc:mysql://localhost:3306/flyway_demo_db (MySQL 5.7)

+---------+---------------------+---------------------+---------+
| Version | Description         | Installed on        | State   |
+---------+---------------------+---------------------+---------+
| 1.0.0   | App version 1.0     | 2017-12-05 21:54:54 | Baselin |
| 1.1.0   | create table demo a | 2017-12-05 21:56:51 | Success |  <--- Stateが変わる
| 1.1.1   | insert data demo a  | 2017-12-05 21:56:51 | Success |  <--- Stateが変わる
+---------+---------------------+---------------------+---------+
```

### バージョンを指定してマイグレーションする

未適用のマイグレーションファイルが複数ある中から、マイグレーションするバージョンの範囲を指定したい場合は、migrateコマンドの`target`オプションにバージョンを指定します。

新しくマイグレーションファイルを作成してsqlディレクトリ下に配置します。

**demo_bテーブルを作成する**

ファイル名：`V1_2_0__create_table_demo_b.sql`

```sql
CREATE TABLE IF NOT EXISTS demo_b (
  id BIGINT NOT NULL AUTO_INCREMENT,
  name VARCHAR(255) NOT NULL,
  PRIMARY KEY (id)
);
```

**demo_bテーブルの初期データを登録する**

ファイル名：`V1_2_1__insert_data_demo_b_someting_a.sql`

```sql
INSERT INTO demo_b (name) VALUES ('someting a test data 1');
INSERT INTO demo_b (name) VALUES ('someting a test data 2');
INSERT INTO demo_b (name) VALUES ('someting a test data 3');
```

この状態でバージョン1.2.0までのマイグレーションを行ってみます。

```bat
> flyway.cmd info
Flyway 4.2.0 by Boxfuse

Database: jdbc:mysql://localhost:3306/flyway_demo_db (MySQL 5.7)

+---------+-------------------------------+---------------------+---------+
| Version | Description                   | Installed on        | State   |
+---------+-------------------------------+---------------------+---------+
| 1.0.0   | App version 1.0               | 2017-12-05 21:54:54 | Baselin |
| 1.1.0   | create table demo a           | 2017-12-05 21:56:51 | Success |
| 1.1.1   | insert data demo a            | 2017-12-05 21:56:51 | Success |
| 1.2.0   | create table demo b           |                     | Pending |  <--- 認識される
| 1.2.1   | insert data demo b someting a |                     | Pending |  <--- 認識される
+---------+-------------------------------+---------------------+---------+
```

demo_bテーブルの作成までしか適用したくないので、migrateコマンドのオプション`target`にバージョン1.2.0を指定します。

```bat
> flyway.cmd migrate -target=1.2.0
Flyway 4.2.0 by Boxfuse

Database: jdbc:mysql://localhost:3306/flyway_demo_db (MySQL 5.7)
Successfully validated 5 migrations (execution time 00:00.019s)
Current version of schema `flyway_demo_db`: 1.1.1
Migrating schema `flyway_demo_db` to version 1.2.0 - create table demo b
Successfully applied 1 migration to schema `flyway_demo_db` (execution time 00:00.230s).
```

指定したバージョンまでしか適用されていないことがわかります。

```bat
> flyway.cmd info
Flyway 4.2.0 by Boxfuse

Database: jdbc:mysql://localhost:3306/flyway_demo_db (MySQL 5.7)

+---------+-------------------------------+---------------------+---------+
| Version | Description                   | Installed on        | State   |
+---------+-------------------------------+---------------------+---------+
| 1.0.0   | App version 1.0               | 2017-12-05 21:54:54 | Baselin |
| 1.1.0   | create table demo a           | 2017-12-05 21:56:51 | Success |
| 1.1.1   | insert data demo a            | 2017-12-05 21:56:51 | Success |
| 1.2.0   | create table demo b           | 2017-12-05 21:59:32 | Success |  <--- Stateが変わる
| 1.2.1   | insert data demo b someting a |                     | Pending |
+---------+-------------------------------+---------------------+---------+
```

## 5.マイグレーションに失敗したとき

migrateコマンドが失敗した場合（構文が正しくないSQLファイルを実行しようとした場合など）は、そのバージョンのステータスがFailedとなります。Flywayはトランザクションのロールバックをサポートしているので、変更内容をすべて取り消します。（ただしDMLなど暗黙的にコミットする場合は対象外です）

わざとマイグレーションを失敗させるために、下記のSQLファイルを用意します。
（2行目のINSERTがSyntaxエラーとなるようになっています。）

ファイル名：`V1_2_2__insert_data_demo_b_someting_b.sql`

```sql
INSERT INTO demo_b (name) VALUES ('someting b test data 1');
INSERT INTO demo_b (name) VALUES (someting b test data 2);
INSERT INTO demo_b (name) VALUES ('someting b test data 3');
```

この状態でmigrateコマンドを実行するとマイグレーションが失敗し、原因となったファイルとSQLが出力されます。

```bat
> flyway.cmd migrate
Flyway 4.2.0 by Boxfuse

Database: jdbc:mysql://localhost:3306/flyway_demo_db (MySQL 5.7)
Successfully validated 6 migrations (execution time 00:00.019s)
Current version of schema `flyway_demo_db`: 1.2.0
Migrating schema `flyway_demo_db` to version 1.2.1 - insert data demo b someting a
Migrating schema `flyway_demo_db` to version 1.2.2 - insert data demo b someting b
ERROR: Migration of schema `flyway_demo_db` to version 1.2.2 - insert data demo b someting b failed! Please restore backups and roll back database and code!
ERROR:
Migration V1_2_2__insert_data_demo_b_someting_b.sql failed
----------------------------------------------------------
SQL State  : 42000
Error Code : 1064
Message    : You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'b test data 2)' at line 1
Query is : INSERT INTO demo_b (name) VALUES (someting b test data 2)
Location   : D:/dev/flyway-4.2.0/sql/V1_2_2__insert_data_demo_b_someting_b.sql (D:\dev\flyway-4.2.0\sql\V1_2_2__insert_data_demo_b_someting_b.sql)
Line       : 2
Statement  : INSERT INTO demo_b (name) VALUES (someting b test data 2)
```

infoコマンドで確認すると、マイグレーションが失敗したバージョンのステータスはFailedになっていることがわかります。

```bat
> flyway.cmd info
Flyway 4.2.0 by Boxfuse

Database: jdbc:mysql://localhost:3306/flyway_demo_db (MySQL 5.7)

+---------+-------------------------------+---------------------+---------+
| Version | Description                   | Installed on        | State   |
+---------+-------------------------------+---------------------+---------+
| 1.0.0   | App version 1.0               | 2017-12-05 21:54:54 | Baselin |
| 1.1.0   | create table demo a           | 2017-12-05 21:56:51 | Success |
| 1.1.1   | insert data demo a            | 2017-12-05 21:56:51 | Success |
| 1.2.0   | create table demo b           | 2017-12-05 21:59:32 | Success |
| 1.2.1   | insert data demo b someting a | 2017-12-05 22:00:43 | Success |
| 1.2.2   | insert data demo b someting b | 2017-12-05 22:00:43 | Failed  |  <--- Stateが変わる
+---------+-------------------------------+---------------------+---------+
```

この例では、マイグレーションファイルのSQL文に原因があるので、そのSQLを修正し再度マイグレーションを行います。
しかしSQLの間違いを修正しただけではmigrateコマンドは失敗します。

```bat
> flyway.cmd migrate
Flyway 4.2.0 by Boxfuse

Database: jdbc:mysql://localhost:3306/flyway_demo_db (MySQL 5.7)
ERROR: Validate failed: Detected failed migration to version 1.2.2 (insert data demo b someting b)
```

Failedのバージョンを再度マイグレーションするには、repairコマンドでステータスをPendingに戻す必要があります。

```bat
> flyway.cmd repair
Flyway 4.2.0 by Boxfuse

Database: jdbc:mysql://localhost:3306/flyway_demo_db (MySQL 5.7)
Successfully repaired metadata table `flyway_demo_db`.`schema_version` (execution time 00:00.067s).
Manual cleanup of the remaining effects the failed migration may still be required.
```

ステータスがPendingへ更新されたので、再度migrateコマンドを実行してマイグレーションを行います。

```bat
> flyway.cmd migrate
Flyway 4.2.0 by Boxfuse

Database: jdbc:mysql://localhost:3306/flyway_demo_db (MySQL 5.7)
Successfully validated 6 migrations (execution time 00:00.020s)
Current version of schema `flyway_demo_db`: 1.2.1
Migrating schema `flyway_demo_db` to version 1.2.2 - insert data demo b someting b
Successfully applied 1 migration to schema `flyway_demo_db` (execution time 00:00.058s).
```

## 6.トランザクションのロールバックについて

トランザクションはサポートしていますが、注意点もあります。
たとえば、1つのマイグレーションファイルにDDLとDMLがセットで記述されているような場合、DMLが失敗した場合にDDLもロールバックされるかはRDBMSの実装によります。一部のRDBMSではDDLもロールバックするものがありますが、しないものもあります。

> [Does Flyway perform a roll back if a migration fails?] (https://flywaydb.org/documentation/faq#rollback)
> 
> Flyway runs each migration in a separate transaction. In case of failure this transaction is rolled back. 

回避策としては、マイグレーションファイルの粒度を細かくしてrepairしやすい状態で運用すればよいようです。

## 7.バージョンの差し込み

マイグレーションの対応漏れが見つかり、後から追加でマイグレーションを行うといった場合を想定しています。

追加するマイグレーションファイルのバージョンを最新にすれば問題はありませんが、最新のバージョンより古いバージョンを持ったマイグレーションファイルを追加するとステータスがIgnoredとして扱われてしまい、そのままではマイグレーションはできません。

下記のマイグレーションファイルをsqlディレクトリ下に配置します。
この変更内容はバージョン1.1.x系に属するのでバージョンを1.1.2とします。

ファイル名：`V1_1_2__add_column_demo_a.sql`

```sql
ALTER TABLE demo_a ADD address TEXT;
```

しかし、この例では適用済みのバージョンは1.2.2まで進んでいるので、追加したマイグレーションファイルのステータスがIgnoredとなります。

```bat
> flyway.cmd info
Flyway 4.2.0 by Boxfuse

Database: jdbc:mysql://localhost:3306/flyway_demo_db (MySQL 5.7)

+---------+-------------------------------+---------------------+---------+
| Version | Description                   | Installed on        | State   |
+---------+-------------------------------+---------------------+---------+
| 1.0.0   | App version 1.0               | 2017-12-05 21:54:54 | Baselin |
| 1.1.0   | create table demo a           | 2017-12-05 21:56:51 | Success |
| 1.1.1   | insert data demo a            | 2017-12-05 21:56:51 | Success |
| 1.1.2   | add column demo a             |                     | Ignored |  <--- Ignoredで認識される
| 1.2.0   | create table demo b           | 2017-12-05 21:59:32 | Success |
| 1.2.1   | insert data demo b someting a | 2017-12-05 22:00:43 | Success |
| 1.2.2   | insert data demo b someting b | 2017-12-05 22:03:07 | Success |
+---------+-------------------------------+---------------------+---------+
```

この状態でmigrateコマンドを実行してもエラーになります。

```bat
> flyway.cmd migrate
Flyway 4.2.0 by Boxfuse

Database: jdbc:mysql://localhost:3306/flyway_demo_db (MySQL 5.7)
ERROR: Validate failed: Detected resolved migration not applied to database: 1.1.2
```

この場合はmigirateコマンドにオプション`outOfOrder`を指定します。

```bat
> flyway.cmd migrate -outOfOrder=true
Flyway 4.2.0 by Boxfuse

Database: jdbc:mysql://localhost:3306/flyway_demo_db (MySQL 5.7)
Successfully validated 7 migrations (execution time 00:00.019s)
Current version of schema `flyway_demo_db`: 1.2.2
WARNING: outOfOrder mode is active. Migration of schema `flyway_demo_db` may not be reproducible.
Migrating schema `flyway_demo_db` to version 1.1.2 - add column demo a [out of order]
Successfully applied 1 migration to schema `flyway_demo_db` (execution time 00:00.476s).
```

オプション`outOfOrder`を指定したバージョンのステータスがOutOrdrとなっていますが、変更内容はテーブルに反映されています。

```bat
> flyway.cmd info
Flyway 4.2.0 by Boxfuse

Database: jdbc:mysql://localhost:3306/flyway_demo_db (MySQL 5.7)

+---------+-------------------------------+---------------------+---------+
| Version | Description                   | Installed on        | State   |
+---------+-------------------------------+---------------------+---------+
| 1.0.0   | App version 1.0               | 2017-12-05 21:54:54 | Baselin |
| 1.1.0   | create table demo a           | 2017-12-05 21:56:51 | Success |
| 1.1.1   | insert data demo a            | 2017-12-05 21:56:51 | Success |
| 1.2.0   | create table demo b           | 2017-12-05 21:59:32 | Success |
| 1.2.1   | insert data demo b someting a | 2017-12-05 22:00:43 | Success |
| 1.2.2   | insert data demo b someting b | 2017-12-05 22:03:07 | Success |
| 1.1.2   | add column demo a             | 2017-12-05 22:06:04 | OutOrdr |  <--- Stateが変わる
+---------+-------------------------------+---------------------+---------+
```

## 8.リピータブルマイグレーションの実行

新しくリピータブルマイグレーションファイルを作成してsqlディレクトリ下に配置します。

**demo_vビューを作成する**

ファイル名：`R__create_view_demo_v.sql`

```sql
CREATE OR REPLACE VIEW demo_v (id, name) AS
SELECT a.id
     , a.name
  FROM demo_a AS a;
```

バージョンを持っていないのでVersionは空欄として表示されます。

```bat
> flyway.cmd info
Flyway 4.2.0 by Boxfuse

Database: jdbc:mysql://localhost:3306/flyway_demo_db (MySQL 5.7)

+---------+-------------------------------+---------------------+---------+
| Version | Description                   | Installed on        | State   |
+---------+-------------------------------+---------------------+---------+
| 1.0.0   | App version 1.0               | 2017-12-05 21:54:54 | Baselin |
| 1.1.0   | create table demo a           | 2017-12-05 21:56:51 | Success |
| 1.1.1   | insert data demo a            | 2017-12-05 21:56:51 | Success |
| 1.2.0   | create table demo b           | 2017-12-05 21:59:32 | Success |
| 1.2.1   | insert data demo b someting a | 2017-12-05 22:00:43 | Success |
| 1.2.2   | insert data demo b someting b | 2017-12-05 22:03:07 | Success |
| 1.1.2   | add column demo a             | 2017-12-05 22:06:04 | OutOrdr |
|         | create view demo v            |                     | Pending |  <--- 認識される
+---------+-------------------------------+---------------------+---------+
```

この状態でマイグレーションを行ってみます。

```bat
> flyway.cmd migrate
Flyway 4.2.0 by Boxfuse

Database: jdbc:mysql://localhost:3306/flyway_demo_db (MySQL 5.7)
Successfully validated 8 migrations (execution time 00:00.024s)
Current version of schema `flyway_demo_db`: 1.2.2
Migrating schema `flyway_demo_db` with repeatable migration create view demo v
Successfully applied 1 migration to schema `flyway_demo_db` (execution time 00:00.106s).
```

```bat
> flyway.cmd info
Flyway 4.2.0 by Boxfuse

Database: jdbc:mysql://localhost:3306/flyway_demo_db (MySQL 5.7)

+---------+-------------------------------+---------------------+---------+
| Version | Description                   | Installed on        | State   |
+---------+-------------------------------+---------------------+---------+
| 1.0.0   | App version 1.0               | 2017-12-05 21:54:54 | Baselin |
| 1.1.0   | create table demo a           | 2017-12-05 21:56:51 | Success |
| 1.1.1   | insert data demo a            | 2017-12-05 21:56:51 | Success |
| 1.2.0   | create table demo b           | 2017-12-05 21:59:32 | Success |
| 1.2.1   | insert data demo b someting a | 2017-12-05 22:00:43 | Success |
| 1.2.2   | insert data demo b someting b | 2017-12-05 22:03:07 | Success |
| 1.1.2   | add column demo a             | 2017-12-05 22:06:04 | OutOrdr |
|         | create view demo v            | 2017-12-05 22:15:41 | Success |  <--- Stateが変わる
+---------+-------------------------------+---------------------+---------+
```

マイグレーション済みのリピータブルマイグレーションファイルを修正すると、またFlywayから新しく認識されます。
これはマイグレーション実行時のファイルのチェックサムと現在のファイルのチェックサムを比較し差異があればファイルが更新されたという判断を行っているためです。
通常のマイグレーションファイルの場合は適用済みのファイルを編集することはありませんが、リピータブルマイグレーションファイルの場合は、変更を同じファイルに対して行います。

この例では、ビューにカラムを1つ追加しています。

```sql
CREATE OR REPLACE VIEW demo_v (id, name, current) AS
SELECT a.id
     , a.name
     , CURRENT_TIMESTAMP(6) AS current
  FROM demo_a AS a;
```

infoコマンドで確認すると新しく認識されていることがわかります。

```bat
> flyway.cmd info
Flyway 4.2.0 by Boxfuse

Database: jdbc:mysql://localhost:3306/flyway_demo_db (MySQL 5.7)

+---------+-------------------------------+---------------------+---------+
| Version | Description                   | Installed on        | State   |
+---------+-------------------------------+---------------------+---------+
| 1.0.0   | App version 1.0               | 2017-12-05 21:54:54 | Baselin |
| 1.1.0   | create table demo a           | 2017-12-05 21:56:51 | Success |
| 1.1.1   | insert data demo a            | 2017-12-05 21:56:51 | Success |
| 1.2.0   | create table demo b           | 2017-12-05 21:59:32 | Success |
| 1.2.1   | insert data demo b someting a | 2017-12-05 22:00:43 | Success |
| 1.2.2   | insert data demo b someting b | 2017-12-05 22:03:07 | Success |
| 1.1.2   | add column demo a             | 2017-12-05 22:06:04 | OutOrdr |
|         | create view demo v            | 2017-12-05 22:15:41 | Outdate |  <--- Stateが変わる
|         | create view demo v            |                     | Pending |  <--- 新しく認識される
+---------+-------------------------------+---------------------+---------+
```

この状態でマイグレーションを行うと、ビューが再作成されます。
なお、ビューを作成するSQLの構文が`CREATE OR REPLACE`でないとエラーになります。Flywayが自動的にdrop and createをしてくれるわけではないので、実行するSQLが反復可能でなければなりません。

```bat
> flyway.cmd migrate
Flyway 4.2.0 by Boxfuse

Database: jdbc:mysql://localhost:3306/flyway_demo_db (MySQL 5.7)
Successfully validated 9 migrations (execution time 00:00.022s)
Current version of schema `flyway_demo_db`: 1.2.2
Migrating schema `flyway_demo_db` with repeatable migration create view demo v
Successfully applied 1 migration to schema `flyway_demo_db` (execution time 00:00.078s).
```

## 9.ベースラインのバージョンを上げる

開発環境のデータベースを新しく作り直す場合に、最新のダンプデータをインポートすることがあると思います。
ダンプデータにschema_versionテーブルが含まれておらず、且つマイグレーションファイルの変更内容を反映している場合では、既存のマイグレーションファイルがmigrateコマンドで適用されてしまいます。このような場合はベースラインのバージョンを上げて既存のマイグレーションファイルを適用外にすることができます。（適用済みのマイグレーションファイルを除外すると、今度はschema_versionとの整合性が取れなくなるので除外はできません。）

新しいベースラインのバージョンを設定します。

```bat
> flyway.cmd baseline -baselineVersion=2.0.0 -baselineDescription="App version 2.0"
Flyway 4.2.0 by Boxfuse

Database: jdbc:mysql://localhost:3306/flyway_demo_db (MySQL 5.7)
Creating Metadata table: `flyway_demo_db`.`schema_version`
Successfully baselined schema with version: 2.0.0
```

新しいベースラインのバージョンが設定された状態です。これにより過去のマイグレーションファイルはmigrateコマンドの適用範囲外となります。

```bat
> flyway.cmd info
Flyway 4.2.0 by Boxfuse

Database: jdbc:mysql://localhost:3306/flyway_demo_db (MySQL 5.7)

+---------+-------------------------------+---------------------+---------+
| Version | Description                   | Installed on        | State   |
+---------+-------------------------------+---------------------+---------+
| 1.1.0   | create table demo a           |                     | <Baseln |
| 1.1.1   | insert data demo a            |                     | <Baseln |
| 1.1.2   | add column demo a             |                     | <Baseln |
| 1.2.0   | create table demo b           |                     | <Baseln |
| 1.2.1   | insert data demo b someting a |                     | <Baseln |
| 1.2.2   | insert data demo b someting b |                     | <Baseln |
| 2.0.0   | App version 2.0               | 2017-12-05 22:31:31 | Baselin |
+---------+-------------------------------+---------------------+---------+
```

## 10.適用済みのマイグレーションファイルを削除する

適用済みのマイグレーションファイルを削除するとステータスがMissingとなり、それ以降のマイグレーションができなくなります。

下記は適用済みのマイグレーションファイルを削除し、新しいマイグレーションファイルを配置した状態です。
この状態でmigrateコマンドを実行してもエラーになります。

対応としては、削除したマイグレーションファイルを元に戻すか、schema_versionテーブルをdropし、もう一度ベースラインの登録から始める必要があります。

```bat
> flyway.cmd info
Flyway 4.2.0 by Boxfuse

Database: jdbc:mysql://localhost:3306/flyway_demo_db (MySQL 5.7)

+---------+-------------------------------+---------------------+---------+
| Version | Description                   | Installed on        | State   |
+---------+-------------------------------+---------------------+---------+
| 1.0.0   | App version 1.0               | 2017-12-05 22:54:23 | Baselin |
| 1.1.0   | create table demo a           | 2017-12-05 22:54:37 | Missing |
| 1.1.1   | insert data demo a            | 2017-12-05 22:54:37 | Missing |
| 1.1.2   | add column demo a             | 2017-12-05 22:54:38 | Missing |
| 1.2.0   | create table demo b           | 2017-12-05 22:54:38 | Missing |
| 1.2.1   | insert data demo b someting a | 2017-12-05 22:54:38 | Missing |
| 1.2.2   | insert data demo b someting b | 2017-12-05 22:54:38 | Missing |
| 1.3.0   | create table demo c           |                     | Pending |
+---------+-------------------------------+---------------------+---------+
```

## 11.マイグレーションファイルの検証

validateコマンドを使うとバージョン管理対象のスキーマの状態とマイグレーションファイルの間に差異がないか検証することができます。
正確にはmigrateコマンドで適用したときのマイグレーションファイルと、現在のマイグレーションファイルに差異があるかをファイルのチェックサムの比較で検証しています。
なのでsqlコマンドで直接テーブルの状態を変えた場合などはvalidateコマンドでは検知できません。

下記の例はマイグレーションファイルを改変した後にvalidateコマンドで検証した結果です。
migrateコマンドで適用した時のファイルのチェックサムと現在のマイグレーションファイルのチェックサムに違いが出たためエラーになります。

```bat
> flyway.cmd validate
Flyway 4.2.0 by Boxfuse

Database: jdbc:mysql://localhost:3306/flyway_demo_db (MySQL 5.7)
ERROR: Validate failed: Migration checksum mismatch for migration 1.2.2
-> Applied to database : 512382482
-> Resolved locally    : -608650376
```

## 12.実行ユーザーの記録

baselineコマンドやmigrateコマンドなど、schema_versionテーブルの更新を伴うような操作を行うときに、そのコマンドの実行者を記録したい場合は`installedBy`オプションにユーザー名を指定します。

```bat
> flyway.cmd migrate -installedBy=rubytomato
```

この情報はinfoコマンドの結果では確認できないので、直接schema_versionテーブルを検索する必要があります。

```sql
> select version,description,installed_by from schema_version;
+---------+---------------------+--------------+
| version | description         | installed_by |
+---------+---------------------+--------------+
| 1.0.0   | App version 1.0     | demo_user    |
| 1.1.0   | create table demo a | rubytomato   |
| 1.1.1   | insert data demo a  | rubytomato   |
| 1.1.2   | add column demo a   | rubytomato   |
+---------+---------------------+--------------+
4 rows in set (0.00 sec)
```

## 13.クリーン

cleanコマンドは管理対象のスキーマからオブジェクトをすべて削除します。（schema_versionも含む）
基本的には開発環境のデータベースを再構築するときに事前に全削除したいといった場合に使用するコマンドだとおもいます。

```bat
> flyway.cmd clean
Flyway 4.2.0 by Boxfuse

Database: jdbc:mysql://localhost:3306/flyway_demo_db (MySQL 5.7)
Successfully cleaned schema `flyway_demo_db` (execution time 00:00.297s)
```

プロダクション環境でもflywayを使ったバージョン管理を行う場合、cleanコマンドを誤って実行してしまう可能性を考えてconfファイルの設定でcleanコマンドを無効化しておくことができます。

```text
# Whether to disabled clean. (default: false)
# flyway.cleanDisabled=
```

cleanコマンドを無効化した状態で実行するとエラーになります。

```bat
> flyway.cmd clean
Flyway 4.2.0 by Boxfuse

Database: jdbc:mysql://localhost:3306/flyway_demo_db (MySQL 5.7)
ERROR: Unable to execute clean as it has been disabled with the "flyway.cleanDisabled" property.
```

# ダウングレードについて

マイグレーションの取り消しができるかですが、出来ないとのことです。

> [What about downgrade scripts/downward migrations?] (https://flywaydb.org/documentation/faq#downgrade)
> 
> Flyway does NOT support downgrade scripts.
While the idea of downgrade scripts (popularized by Rails Migrations) is a nice one in theory,

**2017-12-22追記**

バージョン5のProおよびEnterprise Editionsにダウングレードがサポートされたようです。（無償で利用できるCommunity Editionは未サポート）

詳細はこちら、[Flyway 5.0.0 Released] (https://flywaydb.org/blog/flyway-5.0.0)