CLOVER🍀

That was when it all began.

データベースマイグレーションツール、Flywayを試してみる

これは、なにをしたくて書いたもの?

以前からFlywayを1度試そうと思っていたのですが、そろそろいい加減に、と。

Flywayとは

Flywayは、Javaで実装されたデータベースのマイグレーションツールです。

Homepage - Flyway

GitHub - flyway/flyway: Flyway by Redgate • Database Migrations Made Easy.

Documentation - Flyway by Redgate • Database Migrations Made Easy.

7つのコマンドに基づいて構成されています。

マイグレーションは、SQLやJavaで記述することができ、CLIやJava API、MavenやGradleのプラグインを利用して
実行したり、Spring BootやDropwizardのプラグインなどもあります。

Community Plugins and Integrations - Community Plugins and Integrations - Flyway by Redgate • Database Migrations Made Easy.

サポートされているデータベースは、以下のようです。

f:id:Kazuhira:20211005224250p:plain

Flywayには2つのEditionがあり、Community EditionとTeam Editionがあります。

Download + pricing - Flyway

そこそこ機能差があって、7つのコマンドのうちundoはTeam Editionのみで使えます。

データベースマイグレーションとFlywayの仕組み

Flywayのドキュメントに、どうしてデータベースマイグレーションが必要なのかが書かれています。

Why database migrations - Flyway by Redgate • Database Migrations Made Easy.

データベースは、本番環境だけではなく、開発者個人の環境、CI環境、テスト環境など複数存在することが多いでしょう。
これらのデータベースに対して、変更を管理・反映していく必要があります。

それぞれのデータベースがどのような状態になっているか?変更を行うスクリプトは適用済みか?といった状態を管理したり、
新しくデータベースが稼働する環境が増えた時に設定する時は?といった課題は、開発につきまとう課題です。

マイグレーションツールは、これを解決するためのものです。

Flywayがどのように動作するかは、こちらに書かれています。

How Flyway works - Flyway by Redgate • Database Migrations Made Easy.

Flywayはスキーマを管理するテーブル(スキーマ履歴テーブル)を作成し、こちらでデータベースの状態管理を
行うようです。

Flywayの実行の流れをざっくり書くと、こんな感じみたいです。

Flywayはファイルシステムまたはクラスパスをスキャンして、マイグレーションを確認します。マイグレーションは
SQLまたはJavaで記述されています。

ここで「マイグレーション」というのは、データベースに対する変更のことですね。Flywayではデータベースへの変更を
すべてマイグレーションと呼ぶそうです。

With Flyway all changes to the database are called migrations.

Migrations - Migrations - Flyway by Redgate • Database Migrations Made Easy.

マイグレーションはバージョン番号に基づいて並び替えられ、順番に適用します。
この結果は、スキーマ履歴テーブルに反映されます。

次にFlywayを実行した時には、再度ファイルシステムやクラスパスをスキャンし、マイグレーションを確認します。

検出されたマイグレーションとスキーマ履歴テーブルを確認し、現在適用済みのバージョン以下の場合は
そのマイグレーションは無視されます。

それ以外のマイグレーションはペンディングされ、バージョン番号でソートされた後に適用されます。
そして、スキーマ履歴テーブルに結果が反映されます。

この繰り返し、という感じですね。適用するマイグレーションは、DDL、DMLといった種類は問いません。

マイグレーションの詳細

マイグレーションの詳しい情報は、こちらのページを参照ですね。

Migrations - Migrations - Flyway by Redgate • Database Migrations Made Easy.

マイグレーションには、次の3種類があります。

Undo Migrationは取り消しを表すマイグレーションですが、Team Editionでないと使えません…。

Versioned Migrationが一般的なマイグレーションで、バージョン、説明、チェックサムから成ります。
バージョンは一意である必要があり、説明はマイグレーションがどのようなものかを示す情報になります。
チェックサムはマイグレーション自体の変更検出に使われます。

Versioned Migrationは1度だけ適用され、その内容としてはDDLやDMLなどになります。
その適用順は、バージョン順です。基本的には単調増加する整数で良いのですが、.や_を含んだ柔軟な値を
指定することもできます。

Repeatable Migrationは、説明とチェックサムはあるものの、バージョンのないマイグレーションです。
実行は1度だけではなく、チェックサムが変更される度に再度実行されます。

これは、ビューやストアドプロシージャなどの作成、データの一括登録などが利用用途のようです。

適用順は、Versioned Migrationがすべて実行された後にRepeatable Migrationが実行されるようです。
Repeatable Migration自体の適用順は、説明の順番みたいですね。

これらのマイグレーションは、SQLまたはJavaで実装することになります。

Migrations / SQL-based migrations

Migrations / Java-based migrations

こちらにマイグレーションの命名規則、マイグレーションのディスカバリー、サポートしている構文などが
記載されています。

説明はいったんこれくらいにして、動かしてみることにしましょう。

環境

今回は、Flywayの適用先データベースとしてMySQLを使うことにします。
バージョンは8.0.26を使い、172.17.0.2で動作しているものとします。

Flyway Command Lineツールを使う

まずは、FlywayのComamand Lineツールを使ってみましょう。

Flyway Command-line - First Steps - First Steps: Command-line - Flyway by Redgate • Database Migrations Made Easy.

Spawnというツールもあり、First stepsはこちらを使ったドキュメントになっていますが、今回は使わないことにします。

Spin up instant copies of your dev databases in the cloud for free - Spin up instant copies of your dev databases in the cloud for free - Flyway by Redgate • Database Migrations Made Easy.

現時点の最新版は8.0.0のbetaなので、今回は7.15.0を使うことにします。

ダウンロードして

$ curl -OL https://repo1.maven.org/maven2/org/flywaydb/flyway-commandline/7.15.0/flyway-commandline-7.15.0-linux-x64.tar.gz

展開。

$ tar xf flyway-commandline-7.15.0-linux-x64.tar.gz

こんな感じのディレクトリ構成のようです。

$ find flyway-7.15.0 -maxdepth 1 -type d
flyway-7.15.0
flyway-7.15.0/sql
flyway-7.15.0/drivers
flyway-7.15.0/jre
flyway-7.15.0/lib
flyway-7.15.0/conf
flyway-7.15.0/jars
flyway-7.15.0/licenses

JREも入っているみたいですね。

ディレクトリ内に移動。

$ cd flyway-7.15.0

ヘルプ。

$ ./flyway --help

Javaは、AdoptOpenJDKの11が入っているようです。

$ jre/bin/java --version
openjdk 11.0.2 2019-01-15
OpenJDK Runtime Environment AdoptOpenJDK (build 11.0.2+9)
OpenJDK 64-Bit Server VM AdoptOpenJDK (build 11.0.2+9, mixed mode)

設定ファイルを確認してみます。

conf/flyway.conf

$ grep -vE '#|^$' conf/flyway.conf
flyway.locations=filesystem:sql

デフォルトでは、ファイルシステム上のsqlディレクトリをマイグレーション配置場所に指定しているようです。

設定項目は、こちらを参照。

configuration - Configuration - Flyway by Redgate • Database Migrations Made Easy.

First stepsのドキュメントに合わせて、JDBC接続時のURLとユーザー名、パスワードを設定。

$ grep -vE '#|^$' conf/flyway.conf
flyway.url=jdbc:mysql://172.17.0.2:3306/practice?characterEncoding=utf-8&characterSetResults=utf-8
flyway.user=kazuhira
flyway.password=password
flyway.locations=filesystem:sql

JDBCドライバーは、Flyway自体に含まれています。

$ ll drivers | perl -wp -e 's!kazuhira!xxxxx!g'
合計 58580
drwxrwxr-x 3 xxxxx xxxxx     4096 10月  6 21:40 ./
drwxrwxr-x 9 xxxxx xxxxx     4096 10月  6 21:40 ../
-rw-r--r-- 1 xxxxx xxxxx    19883  9月  6 23:18 aws-secretsmanager-jdbc-1.0.6.jar
-rw-r--r-- 1 xxxxx xxxxx  3683035  9月  6 23:18 derby-10.15.2.0.jar
-rw-r--r-- 1 xxxxx xxxxx   601103  9月  6 23:18 derbyclient-10.15.2.0.jar
-rw-r--r-- 1 xxxxx xxxxx    93688  9月  6 23:18 derbyshared-10.15.2.0.jar
-rw-r--r-- 1 xxxxx xxxxx   264445  9月  6 23:18 derbytools-10.15.2.0.jar
drwxrwxr-x 2 xxxxx xxxxx     4096 10月  6 21:40 gcp/
-rw-r--r-- 1 xxxxx xxxxx   143459  9月  6 23:18 google-cloud-spanner-jdbc-2.2.6.jar
-rw-r--r-- 1 xxxxx xxxxx   346711  9月  6 23:18 google-cloud-storage-1.113.13.jar
-rw-r--r-- 1 xxxxx xxxxx  2303679  9月  6 23:18 h2-1.4.200.jar
-rw-r--r-- 1 xxxxx xxxxx  1623068  9月  6 23:18 hsqldb-2.6.0.jar
-rw-r--r-- 1 xxxxx xxxxx  1161511  9月  6 23:18 jaybird-jdk18-3.0.10.jar
-rw-r--r-- 1 xxxxx xxxxx  1484022  9月  6 23:18 jna-4.5.2.jar
-rw-r--r-- 1 xxxxx xxxxx  2327597  9月  6 23:18 jna-platform-4.5.2.jar
-rw-r--r-- 1 xxxxx xxxxx   317816  9月  6 23:18 jtds-1.3.1.jar
-rw-r--r-- 1 xxxxx xxxxx   632979  9月  6 23:18 mariadb-java-client-2.7.2.jar
-rw-r--r-- 1 xxxxx xxxxx   279641  9月  6 23:18 msal4j-1.10.1.jar
-rw-r--r-- 1 xxxxx xxxxx  1327642  9月  6 23:18 mssql-jdbc-9.2.1.jre8.jar
-rw-r--r-- 1 xxxxx xxxxx  2428323  9月  6 23:18 mysql-connector-java-8.0.24.jar
-rw-r--r-- 1 xxxxx xxxxx  4397918  9月  6 23:18 ojdbc8-19.6.0.0.jar
-rw-r--r-- 1 xxxxx xxxxx  1005078  9月  6 23:18 postgresql-42.2.19.jar
-rw-r--r-- 1 xxxxx xxxxx        0  9月  6 23:12 put-your-jdbc-drivers-here.txt
-rw-r--r-- 1 xxxxx xxxxx 28177186  9月  6 23:18 snowflake-jdbc-3.13.1.jar
-rw-r--r-- 1 xxxxx xxxxx  7296329  9月  6 23:18 sqlite-jdbc-3.34.0.jar

では、使っていきます。

まずは、対象となるMySQLのデータベースになにもないことを確認。

mysql> show tables;
Empty set (0.00 sec)

sqlディレクトリに、マイグレーションを作成します。今回はSQLとして作成しましょう。

sql/V1__create_book_table.sql

create table book (
  isbn varchar(14),
  title varchar(255),
  price int,
  primary key(isbn)
);

マイグレーションの命名規則は、こちらを参照。

Migrations / SQL-based migrations / Naming

マイグレーションの名前は、以下の要素で構成されます。

  • Prefix … V、U、R(マイグレーションの種類)
  • Version … バージョン
  • Separator … 通常、__
  • Description … 説明(アンダースコアやスペースで区切る)
  • Suffix … .sql

今回はV1__create_book_table.sqlで、Version Migration、バージョンが1、説明は「create book table」となっています。

infoコマンドを試してみます。

Info - Info - Flyway by Redgate • Database Migrations Made Easy.

$ ./flyway info
Flyway Teams Edition 7.15.0 by Redgate
Database: jdbc:mysql://172.17.0.2:3306/practice (MySQL 8.0)
----------------------------------------
Flyway Teams features are enabled by default for the next 27 days. Learn more at https://rd.gt/3A4IWym
----------------------------------------
Schema version: << Empty Schema >>

+-----------+---------+-------------------+------+--------------+---------+----------+
| Category  | Version | Description       | Type | Installed On | State   | Undoable |
+-----------+---------+-------------------+------+--------------+---------+----------+
| Versioned | 1       | create book table | SQL  |              | Pending | No       |
+-----------+---------+-------------------+------+--------------+---------+----------+

作成したマイグレーションが検出され、まだペンディングであることが表示されます。

では、migrateコマンドを実行。

Migrate - Migrate - Flyway by Redgate • Database Migrations Made Easy.

$ ./flyway migrate
Flyway Teams Edition 7.15.0 by Redgate
Database: jdbc:mysql://172.17.0.2:3306/practice (MySQL 8.0)
----------------------------------------
Flyway Teams features are enabled by default for the next 27 days. Learn more at https://rd.gt/3A4IWym
----------------------------------------
Successfully validated 1 migration (execution time 00:00.020s)
Creating Schema History table `practice`.`flyway_schema_history` ...
Current version of schema `practice`: << Empty Schema >>
Migrating schema `practice` to version "1 - create book table"
Successfully applied 1 migration to schema `practice`, now at version v1 (execution time 00:00.211s)

マイグレーションが適用され、テーブルが作成されます。

mysql> show tables;
+-----------------------+
| Tables_in_practice    |
+-----------------------+
| book                  |
| flyway_schema_history |
+-----------------------+
2 rows in set (0.00 sec)

スキーマ履歴テーブルもできているので、中身を見てみましょう。

mysql> select * from flyway_schema_history;
+----------------+---------+-------------------+------+---------------------------+-----------+--------------+---------------------+----------------+---------+
| installed_rank | version | description       | type | script                    | checksum  | installed_by | installed_on        | execution_time | success |
+----------------+---------+-------------------+------+---------------------------+-----------+--------------+---------------------+----------------+---------+
|              1 | 1       | create book table | SQL  | V1__create_book_table.sql | 657681960 | kazuhira     | 2021-10-06 13:12:37 |            147 |       1 |
+----------------+---------+-------------------+------+---------------------------+-----------+--------------+---------------------+----------------+---------+
1 row in set (0.00 sec)

適用したマイグレーションの情報が表示されます。

この状態で、validateを実行してローカルとの差を確認してみます。

Validate - Validate - Flyway by Redgate • Database Migrations Made Easy.

$ ./flyway validate
Flyway Teams Edition 7.15.0 by Redgate
Database: jdbc:mysql://172.17.0.2:3306/practice (MySQL 8.0)
----------------------------------------
Flyway Teams features are enabled by default for the next 27 days. Learn more at https://rd.gt/3A4IWym
----------------------------------------
Successfully validated 1 migration (execution time 00:00.022s)

差はありません。

ここで、マイグレーションを追加してみます。バージョンは2にします。

sql/V2__create_account_table.sql

create table account (
  id int,
  name varchar(50),
  registered datetime,
  about varchar(255),
  primary key(id)
);

infoで見ると、ペンディング状態のマイグレーションが追加されています。

$ ./flyway info
Flyway Teams Edition 7.15.0 by Redgate
Database: jdbc:mysql://172.17.0.2:3306/practice (MySQL 8.0)
----------------------------------------
Flyway Teams features are enabled by default for the next 27 days. Learn more at https://rd.gt/3A4IWym
----------------------------------------
Schema version: 1

+-----------+---------+----------------------+------+---------------------+---------+----------+
| Category  | Version | Description          | Type | Installed On        | State   | Undoable |
+-----------+---------+----------------------+------+---------------------+---------+----------+
| Versioned | 1       | create book table    | SQL  | 2021-10-06 13:12:37 | Success | No       |
| Versioned | 2       | create account table | SQL  |                     | Pending | No       |
+-----------+---------+----------------------+------+---------------------+---------+----------+

ここでvalidateを実行するとローカルとデータベースで差があるので、NGになることが確認できます。

$ ./flyway validate
Flyway Teams Edition 7.15.0 by Redgate
Database: jdbc:mysql://172.17.0.2:3306/practice (MySQL 8.0)
----------------------------------------
Flyway Teams features are enabled by default for the next 27 days. Learn more at https://rd.gt/3A4IWym
----------------------------------------
ERROR: Validate failed: Migrations have failed validation
Detected resolved migration not applied to database: 2. To fix this error, either run migrate, or set -ignorePendingMigrations=true.
Need more flexibility with validation rules? Learn more: https://rd.gt/3AbJUZE

再度migrateを実行。

$ ./flyway migrate
Flyway Teams Edition 7.15.0 by Redgate
Database: jdbc:mysql://172.17.0.2:3306/practice (MySQL 8.0)
----------------------------------------
Flyway Teams features are enabled by default for the next 27 days. Learn more at https://rd.gt/3A4IWym
----------------------------------------
Successfully validated 2 migrations (execution time 00:00.037s)
Current version of schema `practice`: 1
Migrating schema `practice` to version "2 - create account table"
Successfully applied 1 migration to schema `practice`, now at version v2 (execution time 00:00.233s)

テーブルが追加されました。

mysql> show tables;
+-----------------------+
| Tables_in_practice    |
+-----------------------+
| account               |
| book                  |
| flyway_schema_history |
+-----------------------+
3 rows in set (0.00 sec)

ここで、試しにバージョン1_1と、2よりも低いマイグレーションを追加してみます。

これをinfoで確認。

$ cp sql/V1__create_book_table.sql sql/V1_1__create_book_table.sql


$ ./flyway info
Flyway Teams Edition 7.15.0 by Redgate
Database: jdbc:mysql://172.17.0.2:3306/practice (MySQL 8.0)
----------------------------------------
Flyway Teams features are enabled by default for the next 28 days. Learn more at https://rd.gt/3A4IWym
----------------------------------------
Schema version: 2

+-----------+---------+----------------------+------+---------------------+---------+----------+
| Category  | Version | Description          | Type | Installed On        | State   | Undoable |
+-----------+---------+----------------------+------+---------------------+---------+----------+
| Versioned | 1       | create book table    | SQL  | 2021-10-06 13:12:37 | Success | No       |
| Versioned | 2       | create account table | SQL  | 2021-10-06 13:26:48 | Success | No       |
| Versioned | 1.1     | create book table    | SQL  |                     | Ignored | No       |
+-----------+---------+----------------------+------+---------------------+---------+----------+

すると、現在のバージョンである2よりも低いので、無視されることが確認できます。

Flywayがバージョンをどのように解釈しているかは、こちらを見るとよさそうです。

https://github.com/flyway/flyway/blob/flyway-7.15.0/flyway-core/src/main/java/org/flywaydb/core/api/MigrationVersion.java

ドキュメントでも十分イメージはつかめますけどね、より詳細に見たい場合は、と。

Migrations / SQL-based migrations / Naming

追加した、無視対象のマイグレーションは削除しておきます。

$ rm sql/V1_1__create_book_table.sql

今度はバージョン3を作成しましょう。データ登録にします。

sql/V3__insert_books.sql

insert into book(isbn, title, price) values('978-4798161488', 'MySQL徹底入門 第4版 MySQL 8.0対応', 4180);
insert into book(isbn, title, price) values('978-4798147406', '詳解MySQL 5.7 止まらぬ進化に乗り遅れないためのテクニカルガイド', 3960);
insert into book(isbn, title, price) values('978-4873116389', '実践ハイパフォーマンスMySQL 第3版', 5280);

migrateを実行。

$ ./flyway migrate
Flyway Teams Edition 7.15.0 by Redgate
Database: jdbc:mysql://172.17.0.2:3306/practice (MySQL 8.0)
----------------------------------------
Flyway Teams features are enabled by default for the next 27 days. Learn more at https://rd.gt/3A4IWym
----------------------------------------
Successfully validated 3 migrations (execution time 00:00.031s)
Current version of schema `practice`: 2
Migrating schema `practice` to version "3 - insert books"
Successfully applied 1 migration to schema `practice`, now at version v3 (execution time 00:00.108s)

データが入りました。

mysql> select * from book;
+----------------+------------------------------------------------------------------------------------------+-------+
| isbn           | title                                                                                    | price |
+----------------+------------------------------------------------------------------------------------------+-------+
| 978-4798147406 | 詳解MySQL 5.7 止まらぬ進化に乗り遅れないためのテクニカルガイド                           |  3960 |
| 978-4798161488 | MySQL徹底入門 第4版 MySQL 8.0対応                                                        |  4180 |
| 978-4873116389 | 実践ハイパフォーマンスMySQL 第3版                                                        |  5280 |
+----------------+------------------------------------------------------------------------------------------+-------+
3 rows in set (0.00 sec)

cleanを試してみましょう。これは、スキーマ内のオブジェクト(テーブル、ビュー、ストアドプロシージャなど)を
破棄してクリーンアップするコマンドです。もちろん、本番環境のデータベースに対して使うべきコマンドではありません。

Clean - Clean - Flyway by Redgate • Database Migrations Made Easy.

$ ./flyway clean
Flyway Teams Edition 7.15.0 by Redgate
Database: jdbc:mysql://172.17.0.2:3306/practice (MySQL 8.0)
----------------------------------------
Flyway Teams features are enabled by default for the next 27 days. Learn more at https://rd.gt/3A4IWym
----------------------------------------
Successfully dropped pre-schema database level objects (execution time 00:00.002s)
Successfully cleaned schema `practice` (execution time 00:00.295s)
Successfully dropped post-schema database level objects (execution time 00:00.001s)

作成したテーブルがキレイになくなりました。

mysql> show tables;
Empty set (0.00 sec)

Repeatable Migrationも使ってみましょう。最後に作成したマイグレーションのPrefixをRにしてバージョンはなくしてみます。

$ mv sql/V3__insert_books.sql sql/R__insert_books.sql

中身は、再実行可能なようにtruncate tableも入れておきます。

sql/R__insert_books.sql

truncate table book;
insert into book(isbn, title, price) values('978-4798161488', 'MySQL徹底入門 第4版 MySQL 8.0対応', 4180);
insert into book(isbn, title, price) values('978-4798147406', '詳解MySQL 5.7 止まらぬ進化に乗り遅れないためのテクニカルガイド', 3960);
insert into book(isbn, title, price) values('978-4873116389', '実践ハイパフォーマンスMySQL 第3版', 5280);

この状態で、migrateを実行。

$ ./flyway migrate
Flyway Teams Edition 7.15.0 by Redgate
Database: jdbc:mysql://172.17.0.2:3306/practice (MySQL 8.0)
----------------------------------------
Flyway Teams features are enabled by default for the next 27 days. Learn more at https://rd.gt/3A4IWym
----------------------------------------
Successfully validated 3 migrations (execution time 00:00.031s)
Creating Schema History table `practice`.`flyway_schema_history` ...
Current version of schema `practice`: << Empty Schema >>
Migrating schema `practice` to version "1 - create book table"
Migrating schema `practice` to version "2 - create account table"
Migrating schema `practice` with repeatable migration "insert books"
Successfully applied 3 migrations to schema `practice`, now at version v2 (execution time 00:01.017s)

データが入りました。

mysql> select * from book;
+----------------+------------------------------------------------------------------------------------------+-------+
| isbn           | title                                                                                    | price |
+----------------+------------------------------------------------------------------------------------------+-------+
| 978-4798147406 | 詳解MySQL 5.7 止まらぬ進化に乗り遅れないためのテクニカルガイド                           |  3960 |
| 978-4798161488 | MySQL徹底入門 第4版 MySQL 8.0対応                                                        |  4180 |
| 978-4873116389 | 実践ハイパフォーマンスMySQL 第3版                                                        |  5280 |
+----------------+------------------------------------------------------------------------------------------+-------+
3 rows in set (0.00 sec)

infoで見てみます。

$ ./flyway info
Flyway Teams Edition 7.15.0 by Redgate
Database: jdbc:mysql://172.17.0.2:3306/practice (MySQL 8.0)
----------------------------------------
Flyway Teams features are enabled by default for the next 27 days. Learn more at https://rd.gt/3A4IWym
----------------------------------------
Schema version: 2

+------------+---------+----------------------+------+---------------------+---------+----------+
| Category   | Version | Description          | Type | Installed On        | State   | Undoable |
+------------+---------+----------------------+------+---------------------+---------+----------+
| Versioned  | 1       | create book table    | SQL  | 2021-10-06 13:45:23 | Success | No       |
| Versioned  | 2       | create account table | SQL  | 2021-10-06 13:45:24 | Success | No       |
| Repeatable |         | insert books         | SQL  | 2021-10-06 13:45:24 | Success |          |
+------------+---------+----------------------+------+---------------------+---------+----------+

データも確認。

mysql> select * from flyway_schema_history;
+----------------+---------+----------------------+------+------------------------------+------------+--------------+---------------------+----------------+---------+
| installed_rank | version | description          | type | script                       | checksum   | installed_by | installed_on        | execution_time | success |
+----------------+---------+----------------------+------+------------------------------+------------+--------------+---------------------+----------------+---------+
|              1 | 1       | create book table    | SQL  | V1__create_book_table.sql    |  657681960 | kazuhira     | 2021-10-06 13:45:23 |            116 |       1 |
|              2 | 2       | create account table | SQL  | V2__create_account_table.sql | 1435889679 | kazuhira     | 2021-10-06 13:45:24 |            275 |       1 |
|              3 | NULL    | insert books         | SQL  | R__insert_books.sql          | -871738101 | kazuhira     | 2021-10-06 13:45:24 |            428 |       1 |
+----------------+---------+----------------------+------+------------------------------+------------+--------------+---------------------+----------------+---------+
3 rows in set (0.00 sec)

ここで、データを追加してみます。

sql/R__insert_books.sql

truncate table book;
insert into book(isbn, title, price) values('978-4798161488', 'MySQL徹底入門 第4版 MySQL 8.0対応', 4180);
insert into book(isbn, title, price) values('978-4798147406', '詳解MySQL 5.7 止まらぬ進化に乗り遅れないためのテクニカルガイド', 3960);
insert into book(isbn, title, price) values('978-4873116389', '実践ハイパフォーマンスMySQL 第3版', 5280);
insert into book(isbn, title, price) values('978-4295000297', 'MySQL 即効クエリチューニング', 1980);

infoで確認してみると、ペンディング状態のマイグレーションが検出されます。

$ ./flyway info
Flyway Teams Edition 7.15.0 by Redgate
Database: jdbc:mysql://172.17.0.2:3306/practice (MySQL 8.0)
----------------------------------------
Flyway Teams features are enabled by default for the next 28 days. Learn more at https://rd.gt/3A4IWym
----------------------------------------
Schema version: 2

+------------+---------+----------------------+------+---------------------+----------+----------+
| Category   | Version | Description          | Type | Installed On        | State    | Undoable |
+------------+---------+----------------------+------+---------------------+----------+----------+
| Versioned  | 1       | create book table    | SQL  | 2021-10-06 13:45:23 | Success  | No       |
| Versioned  | 2       | create account table | SQL  | 2021-10-06 13:45:24 | Success  | No       |
| Repeatable |         | insert books         | SQL  | 2021-10-06 13:45:24 | Outdated |          |
| Repeatable |         | insert books         | SQL  |                     | Pending  |          |
+------------+---------+----------------------+------+---------------------+----------+----------+

migrateを実行してみます。

$ ./flyway migrate

すると、Repeatable Migrationが1レコード追加されます。前に適用したものは、「置き換えられたもの」という
扱いになるようです。

$ ./flyway info
Flyway Teams Edition 7.15.0 by Redgate
Database: jdbc:mysql://172.17.0.2:3306/practice (MySQL 8.0)
----------------------------------------
Flyway Teams features are enabled by default for the next 27 days. Learn more at https://rd.gt/3A4IWym
----------------------------------------
Schema version: 2

+------------+---------+----------------------+------+---------------------+------------+----------+
| Category   | Version | Description          | Type | Installed On        | State      | Undoable |
+------------+---------+----------------------+------+---------------------+------------+----------+
| Versioned  | 1       | create book table    | SQL  | 2021-10-06 13:45:23 | Success    | No       |
| Versioned  | 2       | create account table | SQL  | 2021-10-06 13:45:24 | Success    | No       |
| Repeatable |         | insert books         | SQL  | 2021-10-06 13:45:24 | Superseded |          |
| Repeatable |         | insert books         | SQL  | 2021-10-06 13:51:32 | Success    |          |
+------------+---------+----------------------+------+---------------------+------------+----------+

スキーマ履歴テーブルも確認。

mysql> select * from flyway_schema_history;
+----------------+---------+----------------------+------+------------------------------+-------------+--------------+---------------------+----------------+---------+
| installed_rank | version | description          | type | script                       | checksum    | installed_by | installed_on        | execution_time | success |
+----------------+---------+----------------------+------+------------------------------+-------------+--------------+---------------------+----------------+---------+
|              1 | 1       | create book table    | SQL  | V1__create_book_table.sql    |   657681960 | kazuhira     | 2021-10-06 13:45:23 |            116 |       1 |
|              2 | 2       | create account table | SQL  | V2__create_account_table.sql |  1435889679 | kazuhira     | 2021-10-06 13:45:24 |            275 |       1 |
|              3 | NULL    | insert books         | SQL  | R__insert_books.sql          |  -871738101 | kazuhira     | 2021-10-06 13:45:24 |            428 |       1 |
|              4 | NULL    | insert books         | SQL  | R__insert_books.sql          | -1366018225 | kazuhira     | 2021-10-06 13:51:32 |            175 |       1 |
+----------------+---------+----------------------+------+------------------------------+-------------+--------------+---------------------+----------------+---------+
4 rows in set (0.00 sec)

データが入っていることも確認。

mysql> select * from book;
+----------------+------------------------------------------------------------------------------------------+-------+
| isbn           | title                                                                                    | price |
+----------------+------------------------------------------------------------------------------------------+-------+
| 978-4295000297 | MySQL 即効クエリチューニング                                                             |  1980 |
| 978-4798147406 | 詳解MySQL 5.7 止まらぬ進化に乗り遅れないためのテクニカルガイド                           |  3960 |
| 978-4798161488 | MySQL徹底入門 第4版 MySQL 8.0対応                                                        |  4180 |
| 978-4873116389 | 実践ハイパフォーマンスMySQL 第3版                                                        |  5280 |
+----------------+------------------------------------------------------------------------------------------+-------+
4 rows in set (0.00 sec)

最後にcleanで破棄しておきましょう。

$ ./flyway clean
Flyway Teams Edition 7.15.0 by Redgate
Database: jdbc:mysql://172.17.0.2:3306/practice (MySQL 8.0)
----------------------------------------
Flyway Teams features are enabled by default for the next 27 days. Learn more at https://rd.gt/3A4IWym
----------------------------------------
Successfully dropped pre-schema database level objects (execution time 00:00.001s)
Successfully cleaned schema `practice` (execution time 00:00.279s)
Successfully dropped post-schema database level objects (execution time 00:00.008s)

これで、Command Lineツールを使って基本的な使い方は確認できたのではないでしょうか。

Java APIを使う

最後に、Java APIも使ってみましょう。
先ほどまでFlywayのComnand Lineツールで実行していたことを、Javaで行う感じですね。

ドキュメントは、このあたりを参考に。

API - First Steps - First Steps: API - Flyway by Redgate • Database Migrations Made Easy.

API - API - Flyway by Redgate • Database Migrations Made Easy.

環境。

$ java --version
openjdk 11.0.11 2021-04-20
OpenJDK Runtime Environment (build 11.0.11+9-Ubuntu-0ubuntu2.20.04)
OpenJDK 64-Bit Server VM (build 11.0.11+9-Ubuntu-0ubuntu2.20.04, mixed mode, sharing)


$ mvn --version
Apache Maven 3.8.3 (ff8e977a158738155dc465c6a97ffaf31982d739)
Maven home: $HOME/.sdkman/candidates/maven/current
Java version: 11.0.11, vendor: Ubuntu, runtime: /usr/lib/jvm/java-11-openjdk-amd64
Default locale: ja_JP, platform encoding: UTF-8
OS name: "linux", version: "5.4.0-88-generic", arch: "amd64", family: "unix"

Maven依存関係。FlywayとMySQLのJDBCドライバーです。

    <dependencies>
        <dependency>
            <groupId>org.flywaydb</groupId>
            <artifactId>flyway-core</artifactId>
            <version>7.15.0</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.26</version>
            <scope>runtime</scope>
        </dependency>
    </dependencies>

作成したソースコード。

src/main/java/org/littlewings/flyway/App.java

package org.littlewings.flyway;

import org.flywaydb.core.Flyway;

public class App {
    public static void main(String... args) {
        Flyway flyway =
                Flyway
                        .configure()
                        .dataSource(
                                "jdbc:mysql://172.17.0.2:3306/practice?characterEncoding=utf-8&characterSetResults=utf-8",
                                "kazuhira",
                                "password"
                        )
                        .load();

        flyway.migrate();
    }
}

Flywayクラスのインスタンスを作成して、migrateメソッドなどのFlywayのコマンドに対応するメソッドを
呼び出します。

FlywayクラスのJavadocはこちら。

API: Javadoc - Flyway by Redgate • Database Migrations Made Easy.

今回、設定はデータソース(JDBC URL、ユーザー名、パスワード)のみにとどめています。

マイグレーションは、どこから検出するかというと

flyway.locations - Locations - Flyway by Redgate • Database Migrations Made Easy.

デフォルト値のclasspath:db/migrationとなります。クラスパス上ですね。

Locations / Default

というわけで、今回はsrc/main/resources/db/migrationディレクトリにCommand Lineツールで使った時と同じ
マイグレーション(SQLファイル)を配置します。

$ tree src/main/resources
src/main/resources
└── db
    └── migration
        ├── R__insert_books.sql
        ├── V1__create_book_table.sql
        └── V2__create_account_table.sql

2 directories, 3 files

ちなみに、設定をもうちょっと詳細に行う場合は、FlywayクラスのコンストラクタにConfigurationインターフェースの
実装クラスのインスタンスを渡します。

Configurationインターフェースの実装としては、ClassicConfiguration、FluentConfigurationの2種類があります。

では、実行。

$ mvn compile exec:java -Dexec.mainClass=org.littlewings.flyway.App

ログが出力され、Flywayが実行されている様子がわかります。

[INFO] --- exec-maven-plugin:3.0.0:java (default-cli) @ flyway-example ---
10月 07, 2021 12:29:56 午前 org.flywaydb.core.internal.license.VersionPrinter printVersionOnly
情報: Flyway Community Edition 7.15.0 by Redgate
10月 07, 2021 12:29:56 午前 org.flywaydb.core.internal.database.base.BaseDatabaseType createDatabase
情報: Database: jdbc:mysql://172.17.0.2:3306/practice (MySQL 8.0)
10月 07, 2021 12:29:56 午前 org.flywaydb.core.internal.command.DbValidate validate
情報: Successfully validated 3 migrations (execution time 00:00.022s)
10月 07, 2021 12:29:56 午前 org.flywaydb.core.internal.schemahistory.JdbcTableSchemaHistory create
情報: Creating Schema History table `practice`.`flyway_schema_history` ...
10月 07, 2021 12:29:57 午前 org.flywaydb.core.internal.command.DbMigrate migrateGroup
情報: Current version of schema `practice`: << Empty Schema >>
10月 07, 2021 12:29:57 午前 org.flywaydb.core.internal.command.DbMigrate doMigrateGroup
情報: Migrating schema `practice` to version "1 - create book table"
10月 07, 2021 12:29:57 午前 org.flywaydb.core.internal.command.DbMigrate doMigrateGroup
情報: Migrating schema `practice` to version "2 - create account table"
10月 07, 2021 12:29:57 午前 org.flywaydb.core.internal.command.DbMigrate doMigrateGroup
情報: Migrating schema `practice` with repeatable migration "insert books"
10月 07, 2021 12:29:57 午前 org.flywaydb.core.internal.command.DbMigrate logSummary
情報: Successfully applied 3 migrations to schema `practice`, now at version v2 (execution time 00:00.630s)

データベース側も確認。データも入っていますね。

mysql> show tables;
+-----------------------+
| Tables_in_practice    |
+-----------------------+
| account               |
| book                  |
| flyway_schema_history |
+-----------------------+
3 rows in set (0.00 sec)


mysql> select * from book;
+----------------+------------------------------------------------------------------------------------------+-------+
| isbn           | title                                                                                    | price |
+----------------+------------------------------------------------------------------------------------------+-------+
| 978-4295000297 | MySQL 即効クエリチューニング                                                             |  1980 |
| 978-4798147406 | 詳解MySQL 5.7 止まらぬ進化に乗り遅れないためのテクニカルガイド                           |  3960 |
| 978-4798161488 | MySQL徹底入門 第4版 MySQL 8.0対応                                                        |  4180 |
| 978-4873116389 | 実践ハイパフォーマンスMySQL 第3版                                                        |  5280 |
+----------------+------------------------------------------------------------------------------------------+-------+
4 rows in set (0.00 sec)

これで、Java APIの方も確認できました、と。

まとめ

Flywayを使ったことがなかったので、今回はどういうものかを確認する意味も含めて、ドキュメントの記載内容から
基本的な使い方までを確認してみました。

なんとなくイメージは知っているつもりでしたが、ちゃんと使ってみた方がやっぱり理解が進みますね。

そのうち、Spring BootやQuarkusあたりに組み込んだものと合わせて使ってみたいものです。