FlywayをJavaプログラムから使ってみる、その1
Flywayとは?
Flywayとは、データベースの「マイグレーションツール」と説明しているところが多いのだが、マイグレーション(移行)というよりも、自動スキーマアップデータと呼んだ方が適切だ。
Flywayのやることは要するにこういうことらしい。
- データベースのスキーマを変更したくなった(フィールド追加とか、テーブル追加とか)。
- そのSQLを書いてやる。
- これをFlywayに食わせると、それに即して自動でスキーマ変更をやってくれる。
- これらのSQLをバージョン管理することにより、古いスキーマのDBを自動更新してくれる。
といったものだ。要するに、
- 開発中には、どんどんDBスキーマが変更される。Flywayが開発者全員のDBを自動更新してくれる。
- リリース後に、リリース先が複数の場合にも、いちいち手で対応する必要なし。Flywayが自動更新してくれる。
というものだ。Flywayなどを使わずとも、こういった管理をするのは当然だろう。手作業でやるのは無茶というものだ。
例えば、Flywayを使わない場合であっても、以下のようにするだろう。
- スキーマバージョンを保持する何らかのテーブルを作り、そこに1と書き込む
- バージョン2に移行する場合のSQLを記述し、最新バージョンとして2を書き込む
- プログラム起動時にDBが現在の最新バージョンでなければ、そのSQL(DDL)を実行する
- これを繰り返す
といった具合だ。このようなことをFlywayが自動で面倒みてくれるというわけだ。
Javaプログラムから使用する
検索してみると、ほとんどが「手作業で」Flywayを使うか、あるいはGradle等から起動する説明ばかりでJavaプログラムで自動化する方法が見られない。
スキーマ変更を行うのが開発者のみであればいざしらず、客先(それも複数)で行ってもらうことは想定できない。「バージョンアップしたプログラムを客先に入れ、客が起動したら、自動でスキーマ変更」されねばならないのだ。
そのためには、FlywayをJavaプログラムに組み込み、プログラム起動時に自動で行わねばならない。以下これを見ていく。
これについては、Flyway APIに説明がある。
環境と最低限のプログラム
DBとしては、Windows7-64のmariadb-10.4.6とした。これをインストールする。
次にgradleに次の依存を記述してライブラリをロードする。
dependencies {
compile group: 'org.flywaydb', name: 'flyway-core', version: '5.2.4'
compile group: 'org.mariadb.jdbc', name: 'mariadb-java-client', version: '2.4.2'
}
※後述するが、2.4.2ドライバでは接続できなかった。
Javaプログラムとしては以下だ。
package flywaytest;
import org.flywaydb.core.*;
public class Main {
public static void main(String[]args) throws Exception {
Class.forName("org.mariadb.jdbc.Driver");
String url = "jdbc:mariadb://localhost/mydb?useUnicode=true&characterEncoding=utf8";
Flyway flyway = Flyway.configure().dataSource(url, "root", "パスワード").load();
flyway.migrate();
}
}
当然だが、mydbは存在せず、SQLを一行も書いてないので以下のエラーになる。
7月 13, 2019 7:27:32 午前 org.flywaydb.core.internal.license.VersionPrinter printVersionOnly
情報: Flyway Community Edition 5.2.4 by Boxfuse
Exception in thread "main" org.flywaydb.core.internal.exception.FlywaySqlException:
Unable to obtain connection from database (jdbc:mariadb://localhost/mydb?useUnicode=true&characterEncoding=utf8) for user 'root': Unknown database 'mydb'
---------------------------------------------------------------------------------------------------------------------------------------------------------
SQL State : 42000
Error Code : 1049
Message : Unknown database 'mydb'
at org.flywaydb.core.internal.jdbc.JdbcUtils.openConnection(JdbcUtils.java:60)
at org.flywaydb.core.internal.database.DatabaseFactory.createDatabase(DatabaseFactory.java:72)
at org.flywaydb.core.Flyway.execute(Flyway.java:1670)
at org.flywaydb.core.Flyway.migrate(Flyway.java:1356)
at flywaytest.Main.main(Main.java:11)
おっと、flywayはDBの作成はしてくれないらしい。以下を実行、
create database mydb default character set utf8;
もう一度実行する。
7月 13, 2019 7:50:54 午前 org.flywaydb.core.internal.license.VersionPrinter printVersionOnly
情報: Flyway Community Edition 5.2.4 by Boxfuse
7月 13, 2019 7:50:54 午前 org.flywaydb.core.internal.database.DatabaseFactory createDatabase
情報: Database: jdbc:mariadb://localhost/mydb (MariaDB 10.4)
Exception in thread "main" org.flywaydb.core.api.FlywayException: Unsupported Database: MariaDB 10.4
at org.flywaydb.core.internal.jdbc.DatabaseType.fromDatabaseProductNameAndPostgreSQLVersion(DatabaseType.java:168)
at org.flywaydb.core.internal.jdbc.DatabaseType.fromJdbcConnection(DatabaseType.java:117)
MariaDB 10.4はサポートしていないという。たしかに、現時点(2019/7/13)では10.3までになっている。
これは結構DB種類やバージョンに厳しいようだ。「10.4でもいいじゃないか」というわけにはいかないらしい。
MariaDB 10.3で実行
10.3に変更してみる。が、
情報: Database: jdbc:mariadb://localhost/mydb (MariaDB 10.3)
Exception in thread "main" org.flywaydb.core.api.FlywayException: Unsupported Database: MariaDB 10.3
at org.flywaydb.core.internal.jdbc.DatabaseType.fromDatabaseProductNameAndPostgreSQLVersion(DatabaseType.java:168)
at org.flywaydb.core.internal.jdbc.DatabaseType.fromJdbcConnection(DatabaseType.java:117)
うまくいかない。先のMariaDB Supported Versionsを見てみるとドライバが2.3.0になっているので、これに変更してみる。
dependencies {
compile group: 'org.flywaydb', name: 'flyway-core', version: '5.2.4'
compile group: 'org.mariadb.jdbc', name: 'mariadb-java-client', version: '2.3.0'
}
今回は以下だ。
7月 13, 2019 8:37:31 午前 org.flywaydb.core.internal.license.VersionPrinter printVersionOnly
情報: Flyway Community Edition 5.2.4 by Boxfuse
7月 13, 2019 8:37:31 午前 org.flywaydb.core.internal.database.DatabaseFactory createDatabase
情報: Database: jdbc:mariadb://localhost/mydb (MySQL 10.3)
7月 13, 2019 8:37:31 午前 org.flywaydb.core.internal.command.DbValidate validate
情報: Successfully validated 0 migrations (execution time 00:00.010s)
7月 13, 2019 8:37:31 午前 org.flywaydb.core.internal.schemahistory.JdbcTableSchemaHistory create
情報: Creating Schema History table: `mydb`.`flyway_schema_history`
7月 13, 2019 8:37:31 午前 org.flywaydb.core.internal.command.DbMigrate migrateGroup
情報: Current version of schema `mydb`: << Empty Schema >>
7月 13, 2019 8:37:31 午前 org.flywaydb.core.internal.command.DbMigrate logSummary
情報: Schema `mydb` is up to date. No migration necessary.
何のスキーマも指定していないのだが、DBにはflyway_schema_historyというテーブルが作成されている。
※もしかしたら、mariadb-java-clientのバージョンが2.3.0であれば、10.4でもいけるのかも。
SQLベースマイグレーション
実はFlywayには2つのモードがあり、コマンドライン等でも使えるものはSQLベースマイグレーションというものらしい。これは、一定の命名規約のファイル名による複数のsqlテキストファイルをおいておき、それをFlywayに処理させるというものだ。
Javaプログラムから行う場合にはこの方法も使えるし、SQLファイルではなく、JavaメソッドとしてDDLを実行させるJavaベースマイグレーションというものもあるらしい。Migrationsに説明がある。
とりあえず、SQLベースマイグレーションを行ってみる。単純に、Javaソースにdb.migrationというパッケージを作成し(ここがデフォルト)、その中にマイグレーションSQLファイルをFlywayの命名規則にしたがって入れればよい。
V2019.07.13.01__creating_table.sql
という名称で以下を記述してみる。
CREATE TABLE car (
id INT NOT NULL PRIMARY KEY,
name VARCHAR(80) NOT NULL,
color VARCHAR(80) NOT NULL
);
INSERT INTO car (id, name, color) VALUES (1, 'DeLorean', 'red');
実行すると、たしかにDBが変更されている。
MariaDB [mydb]> show tables;
+-----------------------+
| Tables_in_mydb |
+-----------------------+
| car |
| flyway_schema_history |
+-----------------------+
2 rows in set (0.001 sec)
MariaDB [mydb]> select * from car;
+----+----------+-------+
| id | name | color |
+----+----------+-------+
| 1 | DeLorean | red |
+----+----------+-------+
1 row in set (0.001 sec)
次に、
V2019.07.13.02__changing_table
という名称で以下を書き込む。
alter table car add remarks varchar(80);
INSERT INTO car (id, name, color) VALUES (2, 'Isuzu', 'blue');
実行してみると完全にうまく行っている。いったんDBを削除し、再作成して実行してもうまく行く。
再度MariaDB 10.4.6でやってみる
いったん10.3.16を削除して、10.4.6を再インストールしてやってみると、こんどはうまくいく。どうなってるのか???
※一応「 MariaDB 10.4 is newer than this version of Flyway and support has not been tested」とは警告しているが。。。
7月 13, 2019 8:59:47 午前 org.flywaydb.core.internal.license.VersionPrinter printVersionOnly
情報: Flyway Community Edition 5.2.4 by Boxfuse
7月 13, 2019 8:59:47 午前 org.flywaydb.core.internal.database.DatabaseFactory createDatabase
情報: Database: jdbc:mariadb://localhost/mydb (MySQL 10.4)
7月 13, 2019 8:59:47 午前 org.flywaydb.core.internal.database.base.Database recommendFlywayUpgradeIfNecessary
警告: Flyway upgrade recommended: MariaDB 10.4 is newer than this version of Flyway and support has not been tested.
7月 13, 2019 8:59:47 午前 org.flywaydb.core.internal.command.DbValidate validate
情報: Successfully validated 2 migrations (execution time 00:00.023s)
7月 13, 2019 8:59:47 午前 org.flywaydb.core.internal.schemahistory.JdbcTableSchemaHistory create
情報: Creating Schema History table: `mydb`.`flyway_schema_history`
7月 13, 2019 8:59:47 午前 org.flywaydb.core.internal.command.DbMigrate migrateGroup
情報: Current version of schema `mydb`: << Empty Schema >>
7月 13, 2019 8:59:47 午前 org.flywaydb.core.internal.command.DbMigrate doMigrateGroup
情報: Migrating schema `mydb` to version 2019.07.13.01 - creating table
7月 13, 2019 8:59:47 午前 org.flywaydb.core.internal.command.DbMigrate doMigrateGroup
情報: Migrating schema `mydb` to version 2019.07.13.02 - changing table
7月 13, 2019 8:59:47 午前 org.flywaydb.core.internal.command.DbMigrate logSummary
情報: Successfully applied 2 migrations to schema `mydb` (execution time 00:00.091s)
まとめ
公式ページではMaria DB10.4はサポート対象になっていないが、実際にはうまく行っているようだ。これはMariaDBのバージョンというよりもMaria DBドライバのバージョンに起因するのかもしれない。つまり、
dependencies {
compile group: 'org.flywaydb', name: 'flyway-core', version: '5.2.4'
compile group: 'org.mariadb.jdbc', name: 'mariadb-java-client', version: '2.4.2'
}
では10.3, 10.4の両方とも動作せず、
compile group: 'org.flywaydb', name: 'flyway-core', version: '5.2.4'
compile group: 'org.mariadb.jdbc', name: 'mariadb-java-client', version: '2.3.0'
では、10.3, 10.4の両方とも動作する。
あとは、以下のJavaプログラムを記述し、
package flywaytest;
import org.flywaydb.core.*;
public class Main {
public static void main(String[]args) throws Exception {
Class.forName("org.mariadb.jdbc.Driver");
String url = "jdbc:mariadb://localhost/mydb?useUnicode=true&characterEncoding=utf8";
Flyway flyway = Flyway.configure().dataSource(url, "root", "パスワード").load();
flyway.migrate();
}
}
db.migrationパッケージ内にFlywayの命名規則にしたがったファイルにDDLを記述すればよい。
ディスカッション
コメント一覧
まだ、コメントがありません