これは、なにをしたくて書いたもの?
Flywayのマイグレーションをどう管理するのがいいのかなと悩んだことがあって、ちょっとまとめておこうかなと。
方針?
Gitを使い、ブランチで開発 → マージする、といったフローを組んでいるチーム開発を背景にしています。
こういう感じで考えました。
- マイグレーションファイルのバージョンは日付をベースにする
- 環境ごとにディレクトリを分ける
- DDL(DCLも?)とデータ(DML)でディレクトリを分ける
- (気になるなら)Out Of Orderを許可する
ちょっとずつ書いていきます。
引用しているFlywayのドキュメントは、Flyway 10.17.2時点の情報で参照しています。
マイグレーションファイルのバージョンは日付をベースにする
Flywayのドキュメントで、マイグレーションのページを見るとバージョニングされたマイグレーションファイル名の例で最初に
V2__Add_new_table.sqlといった例が目に入るので、単純増加な整数的なものを想像してしまいます。
Migrations / Versioned Migrations
ですが、実際にはもっと柔軟にバージョンを付与できます。例も書かれています。
- 1
- 001
- 5.2
- 1.2.3.4.5.6.7.8.9
- 205.68
- 20130115113556
- 2013.1.15.11.35.56
- 2013.01.15.11.35.56
単純な増加な整数(もしくはVx.y.zのようなもの)というバージョニングを採用すると、複数人で開発している時にはバージョンの採番で
悩みますし、ブランチのマージのタイミングでバージョンの順序が入れ替わったりして微妙なことになるので、それなら日付をベースにした
バージョニングにした方がいいのかなと思います。
dateコマンドで採番するくらいでもいいのではないでしょうか?
$ date '+%Y%m%d.%H%M%S' 20240828.115208
もちろん、バージョンの後に意味がわかりやすい名前をつけることは必要ですが。
日付をベースにしたバージョニングを使っても、結局マージするタイミングで順番が入れ替わり後からマージされたマイグレーションの
バージョンが古く、エラーになるのでは?という話についてはOut Of Orderで対応することもできます。
環境ごとにディレクトリを分ける
Flywayはクライアントによりますが、デフォルトでclasspath:db/migration(Java API、Maven、Gradleの場合)または
filesystem:sql(CLIの場合)配下にあるマイグレーションファイルを参照します。
Locations - Flyway - Product Documentation
これをいつも適用するマイグレーションを含めたディレクトリと、環境別のディレクトリに分けて管理するとよいのかなと思います。
たとえばこんな感じですね。
db
└── migration
├── common
│ ├── ....sql
│ └── ....sql
├── development
│ ├── ....sql
│ └── ....sql
├── production
│ ├── ....sql
│ └── ....sql
└── staging
├── ....sql
└── ....sql
いつも適用するマイグレーションを含んだものをcommonとすると、プロダクション環境向けには以下の2つをマイグレーションファイルの
配置先として指定するイメージです。
classpath:db/migration/commonclasspath:db/migration/production
マイグレーションファイルの置き場所は分かれますが、ディレクトリの内容をまとめて適用順が決まるのでふつうにバージョンをつけておけば
OKです。
DDL(DCLも?)とデータ(DML)でディレクトリを分ける
環境別にディレクトリを分けた場合、マイグレーションの内容がDDLなのかDMLなのかでディレクトリを分けた方が後々にわかりやすいのかなと
思いまして。
イメージ的にはこんな感じです。
└── db
└── migration
├── data
│ ├── common
│ │ ├── ....sql
│ │ └── ....sql
│ ├── development
│ │ ├── ....sql
│ │ └── ....sql
│ ├── production
│ │ ├── ....sql
│ │ └── ....sql
│ └── staging
│ ├── ....sql
│ └── ....sql
└── ddl
├── common
│ ├── ....sql
│ └── ....sql
├── development
│ ├── ....sql
│ └── ....sql
├── production
│ ├── ....sql
│ └── ....sql
└── staging
├── xxx.sql
└── xxx.sql
DDLがあまり環境別に変わることはないような気はしますが、DCL(DDLではないですが)のようなケースを考えると分けておいた方が
いいのかもしれない、くらいです。
DMLはdataに置きます。こちらは登録するデータなどになるので、環境別に分けたくなると思います。
使い方は環境別にディレクトリを分けた場合の拡張のようなものなので、プロダクション環境向けの場合は以下の4つを
マイグレーションファイルの配置先として指定するイメージです。
classpath:db/migration/ddl/commonclasspath:db/migration/ddl/productionclasspath:db/migration/data/commonclasspath:db/migration/data/production
DDLは全環境で同じなら、こういうのでもいいかもですね。
└── db
└── migration
├── data
│ ├── common
│ │ ├── ....sql
│ │ └── ....sql
│ ├── development
│ │ ├── ....sql
│ │ └── ....sql
│ ├── production
│ │ ├── ....sql
│ │ └── ....sql
│ └── staging
│ ├── ....sql
│ └── ....sql
└── ddl
├── ....sql
└── ....sql
指定はこちら。
classpath:db/migration/ddlclasspath:db/migration/data/commonclasspath:db/migration/data/production
プロダクション用のデータはGitリポジトリー側には含めたくないという場合は、実行時にマウントする前提にしてそのディレクトリを指定、
でしょうか。
(気になるなら)Out Of Orderを許可する
バージョンの時に少し触れましたが、Flywayはマイグレーションを適用した後に最新のバージョンよりも古いバージョンのマイグレーション
ファイルを追加するとデフォルトではエラーになります。
これはチーム開発をしている時に、マイグレーションを含む修正をマージする順番が入れ替わったりした時などに発生します。
たとえば20240820日付のマイグレーションファイルを含む修正と、20240821日付のマイグレーションファイルを含む修正を並行して
行っていたとします。この時、バージョンが新しい20240821日付のマイグレーションが先にマージ・適用されてしまうと、後から取り込まれた
20240820日付のマイグレーションは適用時にエラーになります。
この挙動を変更するのがOut Of Orderです。
Out Of Order - Flyway - Product Documentation
並行して開発している時のマイグレーションの内容に依存関係がないことが前提ですが、Out Of Orderをtrueにすると古いバージョンの
マイグレーションが追加されても適用してくれます。
というわけで
ここまでいろいろ並べてみましたが、簡単にサンプルを作っておこうと思います。
サンプルはSpring Bootで作ることにして、マイグレーションファイルの置き場所はこの構造にすることにします。
└── src
└── main
└── resources
└── db
└── migration
├── data
│ ├── common
│ │ ├── ....sql
│ │ └── ....sql
│ ├── development
│ │ ├── ....sql
│ │ └── ....sql
│ ├── production
│ │ ├── ....sql
│ │ └── ....sql
│ └── staging
│ ├── ....sql
│ └── ....sql
└── ddl
├── ....sql
└── ....sql
環境
今回の環境はこちら。
$ java --version openjdk 21.0.4 2024-07-16 OpenJDK Runtime Environment (build 21.0.4+7-Ubuntu-1ubuntu222.04) OpenJDK 64-Bit Server VM (build 21.0.4+7-Ubuntu-1ubuntu222.04, mixed mode, sharing) $ mvn --version Apache Maven 3.9.9 (8e8579a9e76f7d015ee5ec7bfcdc97d260186937) Maven home: $HOME/.sdkman/candidates/maven/current Java version: 21.0.4, vendor: Ubuntu, runtime: /usr/lib/jvm/java-21-openjdk-amd64 Default locale: ja_JP, platform encoding: UTF-8 OS name: "linux", version: "5.15.0-119-generic", arch: "amd64", family: "unix"
デーベースにはMySQLを使用します。MySQLサーバーは172.17.0.2で動作しているものとします。
MySQL localhost:3306 ssl practice SQL > select version(); +-----------+ | version() | +-----------+ | 8.4.2 | +-----------+ 1 row in set (0.0003 sec)
複数環境を扱うサンプルも作ろうと思うのですが、これについては複数のデータベースまでは用意せず、テーブルをdropして環境を
リセットしながら試していこうと思います。
Spring Bootプロジェクトを作成する
それでは、Flywayを使うSpring Bootプロジェクトを作成します。
Flywayが実行できればよいので、依存関係にはjdbcとflyway、mysqlを含めます。
$ curl -s https://start.spring.io/starter.tgz \ -d bootVersion=3.3.3 \ -d javaVersion=21 \ -d type=maven-project \ -d name=flyway-migrations \ -d groupId=org.littlewings \ -d artifactId=flyway-migrations \ -d version=0.0.1-SNAPSHOT \ -d packageName=org.littlewings.spring.flyway \ -d dependencies=jdbc,flyway,mysql \ -d baseDir=flyway-migrations | tar zxvf -
生成されたプロジェクト内に移動。
$ cd flyway-migrations
依存関係などはこのようになっています。
<properties> <java.version>21</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>org.flywaydb</groupId> <artifactId>flyway-core</artifactId> </dependency> <dependency> <groupId>org.flywaydb</groupId> <artifactId>flyway-mysql</artifactId> </dependency> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
生成されたディレクトリおよびファイル。Flyway用のディレクトリが最初からありますね。
$ tree -a
.
├── .gitignore
├── .mvn
│ └── wrapper
│ └── maven-wrapper.properties
├── HELP.md
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
├── main
│ ├── java
│ │ └── org
│ │ └── littlewings
│ │ └── spring
│ │ └── flyway
│ │ └── FlywayMigrationsApplication.java
│ └── resources
│ ├── application.properties
│ └── db
│ └── migration
└── test
└── java
└── org
└── littlewings
└── spring
└── flyway
└── FlywayMigrationsApplicationTests.java
18 directories, 9 files
$ rm src/main/java/org/littlewings/spring/flyway/FlywayMigrationsApplication.java src/test/java/org/littlewings/spring/flyway/FlywayMigrationsApplicationTests.java
mainメソッドを持ったクラスの作成。
src/main/java/org/littlewings/spring/flyway/App.java
package org.littlewings.spring.flyway; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class App { public static void main(String... args) { SpringApplication.run(App.class, args); } }
application.propertiesには、ひとまずデータベース接続に関する情報を定義しておきます。
src/main/resources/application.properties
spring.application.name=flyway-migrations spring.datasource.url=jdbc:mysql://172.17.0.2:3306/practice?characterEncoding=utf-8&connectionCollation=utf8mb4_0900_bin spring.datasource.username=kazuhira spring.datasource.password=password
Flywayの設定とマイグレーションの作成
では、Flywayに関する設定とマイグレーションの作成を行っていきましょう。
まずはディレクトリの作成。
$ mkdir src/main/resources/db/migration/{ddl,data}
$ mkdir src/main/resources/db/migration/data/{common,development,production}
環境数は2つにしておきましょう。
まずはこう用意しました。
$ tree src/main/resources/db/migration
src/main/resources/db/migration
├── data
│ ├── common
│ │ └── V20240825.150000__add_people_data.sql
│ ├── development
│ │ └── V20240825.180000__add_people_data.sql
│ └── production
│ └── V20240825.210000__add_people_data.sql
└── ddl
├── V20240825.120000__create_person_table.sql
└── V20240827.150000__create_book_table.sql
5 directories, 5 files
DDLは人と書籍。
src/main/resources/db/migration/ddl/V20240825.120000__create_person_table.sql
create table person( id int, last_name varchar(20), first_name varchar(20), age int primary key(id) );
src/main/resources/db/migration/ddl/V20240827.150000__create_book_table.sql
create table book ( isbn varchar(14), title varchar(200), price int, primary key(isbn) );
バージョンは少し飛ばしてあります。
データは、共通に磯野家の人たち(親除く)。
src/main/resources/db/migration/data/common/V20240825.150000__add_people_data.sql
insert into person(id, last_name, first_name, age) values(1, 'フグ田', 'サザエ', 24); insert into person(id, last_name, first_name, age) values(2, 'フグ田', 'マスオ', 28); insert into person(id, last_name, first_name, age) values(3, '磯野', 'カツオ', 11); insert into person(id, last_name, first_name, age) values(4, '磯野', 'ワカメ', 9); insert into person(id, last_name, first_name, age) values(5, 'フグ田', 'タラオ', 3);
developmentに波野家。
src/main/resources/db/migration/data/development/V20240825.180000__add_people_data.sql
insert into person(id, last_name, first_name, age) values(6, '波野', 'ノリスケ', 24); insert into person(id, last_name, first_name, age) values(7, '波野', 'タイコ', 22); insert into person(id, last_name, first_name, age) values(8, '波野', 'イクラ', 1);
productionだと磯野家が全員揃います。
src/main/resources/db/migration/data/production/V20240825.210000__add_people_data.sql
insert into person(id, last_name, first_name, age) values(6, '磯野', '波平', 54); insert into person(id, last_name, first_name, age) values(7, '磯野', 'フネ', 50);
データの良し悪しについては置いておきます…。
これに合わせて、Flywayの設定を行います。
Common Application Properties / Data Migration Properties
こんな感じになりました。
src/main/resources/application.properties
spring.application.name=flyway-migrations spring.datasource.url=jdbc:mysql://172.17.0.2:3306/practice?characterEncoding=utf-8&connectionCollation=utf8mb4_0900_bin spring.datasource.username=kazuhira spring.datasource.password=password ## Flyway spring.flyway.fail-on-missing-locations=true ### マイグレーションの配置先 spring.flyway.locations=classpath:db/migration/ddl,classpath:db/migration/data/common,classpath:db/migration/data/development ### Out Of Order spring.flyway.out-of-order=false ### マイグレーションの命名規則の確認 spring.flyway.validate-migration-naming=true
ひとまずポイントはここだけですね。
### マイグレーションの配置先 spring.flyway.locations=classpath:db/migration/ddl,classpath:db/migration/data/common,classpath:db/migration/data/development
以下の3つをマイグレーションの配置先に指定しています。
classpath:db/migration/ddlclasspath:db/migration/data/commonclasspath:db/migration/data/development
では、パッケージングして実行。
$ mvn package $ java -jar target/flyway-migrations-0.0.1-SNAPSHOT.jar
Flywayが実行されました。
2024-08-28T15:45:12.997+09:00 INFO 26843 --- [flyway-migrations] [ main] org.flywaydb.core.FlywayExecutor : Database: jdbc:mysql://172.17.0.2:3306/practice (MySQL 8.4) 2024-08-28T15:45:13.145+09:00 WARN 26843 --- [flyway-migrations] [ main] o.f.c.internal.database.base.Database : Flyway upgrade recommended: MySQL 8.4 is newer than this version of Flyway and support has not been tested. The latest supported version of MySQL is 8.1. 2024-08-28T15:45:13.199+09:00 INFO 26843 --- [flyway-migrations] [ main] o.f.c.i.s.JdbcTableSchemaHistory : Schema history table `practice`.`flyway_schema_history` does not exist yet 2024-08-28T15:45:13.206+09:00 INFO 26843 --- [flyway-migrations] [ main] o.f.core.internal.command.DbValidate : Successfully validated 4 migrations (execution time 00:00.044s) 2024-08-28T15:45:13.265+09:00 INFO 26843 --- [flyway-migrations] [ main] o.f.c.i.s.JdbcTableSchemaHistory : Creating Schema History table `practice`.`flyway_schema_history` ... 2024-08-28T15:45:13.540+09:00 INFO 26843 --- [flyway-migrations] [ main] o.f.core.internal.command.DbMigrate : Current version of schema `practice`: << Empty Schema >> 2024-08-28T15:45:13.552+09:00 INFO 26843 --- [flyway-migrations] [ main] o.f.core.internal.command.DbMigrate : Migrating schema `practice` to version "20240825.120000 - create person table" 2024-08-28T15:45:13.738+09:00 INFO 26843 --- [flyway-migrations] [ main] o.f.core.internal.command.DbMigrate : Migrating schema `practice` to version "20240825.150000 - add people data" 2024-08-28T15:45:13.812+09:00 INFO 26843 --- [flyway-migrations] [ main] o.f.core.internal.command.DbMigrate : Migrating schema `practice` to version "20240825.180000 - add people data" 2024-08-28T15:45:13.855+09:00 INFO 26843 --- [flyway-migrations] [ main] o.f.core.internal.command.DbMigrate : Migrating schema `practice` to version "20240827.150000 - create book table" 2024-08-28T15:45:14.012+09:00 INFO 26843 --- [flyway-migrations] [ main] o.f.core.internal.command.DbMigrate : Successfully applied 4 migrations to schema `practice`, now at version v20240827.150000 (execution time 00:00.254s)
テーブルの状態を確認してみます。
MySQL localhost:3306 ssl practice SQL > show tables; +-----------------------+ | Tables_in_practice | +-----------------------+ | book | | flyway_schema_history | | person | +-----------------------+ 3 rows in set (0.0014 sec)
適用されたマイグレーションの一覧。
MySQL localhost:3306 ssl practice SQL > select * from flyway_schema_history; +----------------+-----------------+---------------------+------+-------------------------------------------+------------+--------------+---------------------+----------------+---------+ | installed_rank | version | description | type | script | checksum | installed_by | installed_on | execution_time | success | +----------------+-----------------+---------------------+------+-------------------------------------------+------------+--------------+---------------------+----------------+---------+ | 1 | 20240825.120000 | create person table | SQL | V20240825.120000__create_person_table.sql | -123870336 | kazuhira | 2024-08-28 06:45:13 | 114 | 1 | | 2 | 20240825.150000 | add people data | SQL | V20240825.150000__add_people_data.sql | -181951584 | kazuhira | 2024-08-28 06:45:13 | 11 | 1 | | 3 | 20240825.180000 | add people data | SQL | V20240825.180000__add_people_data.sql | -745607530 | kazuhira | 2024-08-28 06:45:13 | 32 | 1 | | 4 | 20240827.150000 | create book table | SQL | V20240827.150000__create_book_table.sql | 1689297802 | kazuhira | 2024-08-28 06:45:13 | 97 | 1 | +----------------+-----------------+---------------------+------+-------------------------------------------+------------+--------------+---------------------+----------------+---------+ 4 rows in set (0.0005 sec)
DDLとcommonとdevelopmentのデータのみが適用されているはずです。
データで確認してみましょう。
MySQL localhost:3306 ssl practice SQL > select * from person; +----+-----------+------------+-----+ | id | last_name | first_name | age | +----+-----------+------------+-----+ | 1 | フグ田 | サザエ | 24 | | 2 | フグ田 | マスオ | 28 | | 3 | 磯野 | カツオ | 11 | | 4 | 磯野 | ワカメ | 9 | | 5 | フグ田 | タラオ | 3 | | 6 | 波野 | ノリスケ | 24 | | 7 | 波野 | タイコ | 22 | | 8 | 波野 | イクラ | 1 | +----+-----------+------------+-----+ 8 rows in set (0.0005 sec)
OKですね。
もうひとつの方にはデータは入れていません。
MySQL localhost:3306 ssl practice SQL > select * from book; Empty set (0.0010 sec)
ここで、すべてのテーブルをdropします。
MySQL localhost:3306 ssl practice SQL > drop table flyway_schema_history;drop table person;drop table book;
マイグレーションの配置先を、環境変数で切り替えてみましょう。
$ export SPRING_FLYWAY_LOCATIONS=classpath:db/migration/ddl,classpath:db/migration/data/common,classpath:db/migration/data/production
つまり、マイグレーションの配置先はこうなっています。
classpath:db/migration/ddlclasspath:db/migration/data/commonclasspath:db/migration/data/production
developmentがproductionに変わったわけですね。
実行します。
$ java -jar target/flyway-migrations-0.0.1-SNAPSHOT.jar
実行時のログ。
2024-08-28T15:49:09.550+09:00 INFO 27033 --- [flyway-migrations] [ main] org.flywaydb.core.FlywayExecutor : Database: jdbc:mysql://172.17.0.2:3306/practice (MySQL 8.4) 2024-08-28T15:49:09.653+09:00 WARN 27033 --- [flyway-migrations] [ main] o.f.c.internal.database.base.Database : Flyway upgrade recommended: MySQL 8.4 is newer than this version of Flyway and support has not been tested. The latest supported version of MySQL is 8.1. 2024-08-28T15:49:09.696+09:00 INFO 27033 --- [flyway-migrations] [ main] o.f.c.i.s.JdbcTableSchemaHistory : Schema history table `practice`.`flyway_schema_history` does not exist yet 2024-08-28T15:49:09.702+09:00 INFO 27033 --- [flyway-migrations] [ main] o.f.core.internal.command.DbValidate : Successfully validated 4 migrations (execution time 00:00.032s) 2024-08-28T15:49:09.731+09:00 INFO 27033 --- [flyway-migrations] [ main] o.f.c.i.s.JdbcTableSchemaHistory : Creating Schema History table `practice`.`flyway_schema_history` ... 2024-08-28T15:49:10.004+09:00 INFO 27033 --- [flyway-migrations] [ main] o.f.core.internal.command.DbMigrate : Current version of schema `practice`: << Empty Schema >> 2024-08-28T15:49:10.018+09:00 INFO 27033 --- [flyway-migrations] [ main] o.f.core.internal.command.DbMigrate : Migrating schema `practice` to version "20240825.120000 - create person table" 2024-08-28T15:49:10.173+09:00 INFO 27033 --- [flyway-migrations] [ main] o.f.core.internal.command.DbMigrate : Migrating schema `practice` to version "20240825.150000 - add people data" 2024-08-28T15:49:10.224+09:00 INFO 27033 --- [flyway-migrations] [ main] o.f.core.internal.command.DbMigrate : Migrating schema `practice` to version "20240825.210000 - add people data" 2024-08-28T15:49:10.341+09:00 INFO 27033 --- [flyway-migrations] [ main] o.f.core.internal.command.DbMigrate : Migrating schema `practice` to version "20240827.150000 - create book table" 2024-08-28T15:49:10.542+09:00 INFO 27033 --- [flyway-migrations] [ main] o.f.core.internal.command.DbMigrate : Successfully applied 4 migrations to schema `practice`, now at version v20240827.150000 (execution time 00:00.253s)
適用されたマイグレーションの一覧。
MySQL localhost:3306 ssl practice SQL > select * from flyway_schema_history; +----------------+-----------------+---------------------+------+-------------------------------------------+-------------+--------------+---------------------+----------------+---------+ | installed_rank | version | description | type | script | checksum | installed_by | installed_on | execution_time | success | +----------------+-----------------+---------------------+------+-------------------------------------------+-------------+--------------+---------------------+----------------+---------+ | 1 | 20240825.120000 | create person table | SQL | V20240825.120000__create_person_table.sql | -123870336 | kazuhira | 2024-08-28 06:49:10 | 106 | 1 | | 2 | 20240825.150000 | add people data | SQL | V20240825.150000__add_people_data.sql | -181951584 | kazuhira | 2024-08-28 06:49:10 | 11 | 1 | | 3 | 20240825.210000 | add people data | SQL | V20240825.210000__add_people_data.sql | -1450894877 | kazuhira | 2024-08-28 06:49:10 | 7 | 1 | | 4 | 20240827.150000 | create book table | SQL | V20240827.150000__create_book_table.sql | 1689297802 | kazuhira | 2024-08-28 06:49:10 | 129 | 1 | +----------------+-----------------+---------------------+------+-------------------------------------------+-------------+--------------+---------------------+----------------+---------+ 4 rows in set (0.0005 sec)
データを確認してみます。
MySQL localhost:3306 ssl practice SQL > select * from person; +----+-----------+------------+-----+ | id | last_name | first_name | age | +----+-----------+------------+-----+ | 1 | フグ田 | サザエ | 24 | | 2 | フグ田 | マスオ | 28 | | 3 | 磯野 | カツオ | 11 | | 4 | 磯野 | ワカメ | 9 | | 5 | フグ田 | タラオ | 3 | | 6 | 磯野 | 波平 | 54 | | 7 | 磯野 | フネ | 50 | +----+-----------+------------+-----+ 7 rows in set (0.0004 sec)
development用のデータはなくなり、productionのデータが追加されました。
OKですね。
ところで、よく見るとFlywayはMySQL 8.4をまだサポートしていないみたいですね…。
2024-08-28T15:45:13.145+09:00 WARN 26843 --- [flyway-migrations] [ main] o.f.c.internal.database.base.Database : Flyway upgrade recommended: MySQL 8.4 is newer than this version of Flyway and support has not been tested. The latest supported version of MySQL is 8.1.
確認時点だと、確かにそうでした。
Verified Versions: 5.7, 8.0, 8.1
MySQL - Flyway - Product Documentation
Out Of Orderを試す
最後にOut Of Orderを試してみましょう。
マイグレーションは、developmentで適用済みとします。
つまり、この状態ですね。
MySQL localhost:3306 ssl practice SQL > select * from flyway_schema_history; +----------------+-----------------+---------------------+------+-------------------------------------------+------------+--------------+---------------------+----------------+---------+ | installed_rank | version | description | type | script | checksum | installed_by | installed_on | execution_time | success | +----------------+-----------------+---------------------+------+-------------------------------------------+------------+--------------+---------------------+----------------+---------+ | 1 | 20240825.120000 | create person table | SQL | V20240825.120000__create_person_table.sql | -123870336 | kazuhira | 2024-08-28 06:53:31 | 112 | 1 | | 2 | 20240825.150000 | add people data | SQL | V20240825.150000__add_people_data.sql | -181951584 | kazuhira | 2024-08-28 06:53:31 | 9 | 1 | | 3 | 20240825.180000 | add people data | SQL | V20240825.180000__add_people_data.sql | -745607530 | kazuhira | 2024-08-28 06:53:31 | 6 | 1 | | 4 | 20240827.150000 | create book table | SQL | V20240827.150000__create_book_table.sql | 1689297802 | kazuhira | 2024-08-28 06:53:31 | 82 | 1 | +----------------+-----------------+---------------------+------+-------------------------------------------+------------+--------------+---------------------+----------------+---------+ 4 rows in set (0.0004 sec) MySQL localhost:3306 ssl practice SQL > select * from person; +----+-----------+------------+-----+ | id | last_name | first_name | age | +----+-----------+------------+-----+ | 1 | フグ田 | サザエ | 24 | | 2 | フグ田 | マスオ | 28 | | 3 | 磯野 | カツオ | 11 | | 4 | 磯野 | ワカメ | 9 | | 5 | フグ田 | タラオ | 3 | | 6 | 波野 | ノリスケ | 24 | | 7 | 波野 | タイコ | 22 | | 8 | 波野 | イクラ | 1 | +----+-----------+------------+-----+ 8 rows in set (0.0005 sec)
ここで最後のマイグレーションファイルの日付は20240827でしたが、20240826のものを割り込ませてみます。
src/main/resources/db/migration/ddl/V20240826.180000__create_category_table.sql
create table category ( id varchar(3), name varchar(20), primary key(id) );
パッケージングして実行。
$ mvn package $ java -jar target/flyway-migrations-0.0.1-SNAPSHOT.jar
すると、未適用のマイグレーションが検出されたということで失敗します。
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'flywayInitializer' defined in class path resource [org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration$FlywayConfiguration.class]: Validate failed: Migrations have failed validation
Detected resolved migration not applied to database: 20240826.180000.
To ignore this migration, set -ignoreMigrationPatterns='*:ignored'. To allow executing this migration, set -outOfOrder=true.
Need more flexibility with validation rules? Learn more: https://rd.gt/3AbJUZE
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1806) ~[spring-beans-6.1.12.jar!/:6.1.12]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600) ~[spring-beans-6.1.12.jar!/:6.1.12]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:522) ~[spring-beans-6.1.12.jar!/:6.1.12]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:337) ~[spring-beans-6.1.12.jar!/:6.1.12]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-6.1.12.jar!/:6.1.12]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:335) ~[spring-beans-6.1.12.jar!/:6.1.12]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[spring-beans-6.1.12.jar!/:6.1.12]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:313) ~[spring-beans-6.1.12.jar!/:6.1.12]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[spring-beans-6.1.12.jar!/:6.1.12]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:975) ~[spring-beans-6.1.12.jar!/:6.1.12]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:971) ~[spring-context-6.1.12.jar!/:6.1.12]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:625) ~[spring-context-6.1.12.jar!/:6.1.12]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) ~[spring-boot-3.3.3.jar!/:3.3.3]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:456) ~[spring-boot-3.3.3.jar!/:3.3.3]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:335) ~[spring-boot-3.3.3.jar!/:3.3.3]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1363) ~[spring-boot-3.3.3.jar!/:3.3.3]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1352) ~[spring-boot-3.3.3.jar!/:3.3.3]
at org.littlewings.spring.flyway.App.main(App.java:9) ~[!/:0.0.1-SNAPSHOT]
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[na:na]
at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:102) ~[flyway-migrations-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT]
at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:64) ~[flyway-migrations-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT]
at org.springframework.boot.loader.launch.JarLauncher.main(JarLauncher.java:40) ~[flyway-migrations-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT]
Caused by: org.flywaydb.core.api.exception.FlywayValidateException: Validate failed: Migrations have failed validation
Detected resolved migration not applied to database: 20240826.180000.
To ignore this migration, set -ignoreMigrationPatterns='*:ignored'. To allow executing this migration, set -outOfOrder=true.
Need more flexibility with validation rules? Learn more: https://rd.gt/3AbJUZE
at org.flywaydb.core.Flyway.lambda$migrate$0(Flyway.java:160) ~[flyway-core-10.10.0.jar!/:na]
at org.flywaydb.core.FlywayExecutor.execute(FlywayExecutor.java:205) ~[flyway-core-10.10.0.jar!/:na]
at org.flywaydb.core.Flyway.migrate(Flyway.java:147) ~[flyway-core-10.10.0.jar!/:na]
at org.springframework.boot.autoconfigure.flyway.FlywayMigrationInitializer.afterPropertiesSet(FlywayMigrationInitializer.java:66) ~[spring-boot-autoconfigure-3.3.3.jar!/:3.3.3]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1853) ~[spring-beans-6.1.12.jar!/:6.1.12]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1802) ~[spring-beans-6.1.12.jar!/:6.1.12]
... 22 common frames omitted
この部分ですね。
Validate failed: Migrations have failed validation
Detected resolved migration not applied to database: 20240826.180000.
これをそのまま適用してもいいよという場合は、メッセージに書かれているように無視するかOut Of Orderをtrueにします。
To ignore this migration, set -ignoreMigrationPatterns='*:ignored'. To allow executing this migration, set -outOfOrder=true.
今回はOut Of Orderをtrueにしましょう。application.propertiesをこう変更します。
### Out Of Order spring.flyway.out-of-order=true
環境変数で指定したりして、一時的に切り替えてもよいでしょう。
$ export SPRING_FLYWAY_OUTOFORDER=true
(application.propertiesを変更した場合は、パッケージングして)実行。
$ mvn package $ java -jar target/flyway-migrations-0.0.1-SNAPSHOT.jar
「outOfOrder mode is active.」と表示され、マイグレーションを適用してくれます。
2024-08-28T15:59:20.540+09:00 INFO 27655 --- [flyway-migrations] [ main] org.flywaydb.core.FlywayExecutor : Database: jdbc:mysql://172.17.0.2:3306/practice (MySQL 8.4) 2024-08-28T15:59:20.633+09:00 WARN 27655 --- [flyway-migrations] [ main] o.f.c.internal.database.base.Database : Flyway upgrade recommended: MySQL 8.4 is newer than this version of Flyway and support has not been tested. The latest supported version of MySQL is 8.1. 2024-08-28T15:59:20.682+09:00 INFO 27655 --- [flyway-migrations] [ main] o.f.core.internal.command.DbValidate : Successfully validated 5 migrations (execution time 00:00.037s) 2024-08-28T15:59:20.702+09:00 INFO 27655 --- [flyway-migrations] [ main] o.f.core.internal.command.DbMigrate : Current version of schema `practice`: 20240827.150000 2024-08-28T15:59:20.702+09:00 WARN 27655 --- [flyway-migrations] [ main] o.f.core.internal.command.DbMigrate : outOfOrder mode is active. Migration of schema `practice` may not be reproducible. 2024-08-28T15:59:20.724+09:00 INFO 27655 --- [flyway-migrations] [ main] o.f.core.internal.command.DbMigrate : Migrating schema `practice` to version "20240826.180000 - create category table" [out of order] 2024-08-28T15:59:21.088+09:00 INFO 27655 --- [flyway-migrations] [ main] o.f.core.internal.command.DbMigrate : Successfully applied 1 migration to schema `practice`, now at version v20240826.180000 (execution time 00:00.219s)
確認してみましょう。
MySQL localhost:3306 ssl practice SQL > show tables; +-----------------------+ | Tables_in_practice | +-----------------------+ | book | | category | | flyway_schema_history | | person | +-----------------------+ 4 rows in set (0.0013 sec)
テーブルはできています。
適用されたマイグレーションの一覧。
MySQL localhost:3306 ssl practice SQL > select * from flyway_schema_history; +----------------+-----------------+-----------------------+------+---------------------------------------------+------------+--------------+---------------------+----------------+---------+ | installed_rank | version | description | type | script | checksum | installed_by | installed_on | execution_time | success | +----------------+-----------------+-----------------------+------+---------------------------------------------+------------+--------------+---------------------+----------------+---------+ | 1 | 20240825.120000 | create person table | SQL | V20240825.120000__create_person_table.sql | -123870336 | kazuhira | 2024-08-28 06:53:31 | 112 | 1 | | 2 | 20240825.150000 | add people data | SQL | V20240825.150000__add_people_data.sql | -181951584 | kazuhira | 2024-08-28 06:53:31 | 9 | 1 | | 3 | 20240825.180000 | add people data | SQL | V20240825.180000__add_people_data.sql | -745607530 | kazuhira | 2024-08-28 06:53:31 | 6 | 1 | | 4 | 20240827.150000 | create book table | SQL | V20240827.150000__create_book_table.sql | 1689297802 | kazuhira | 2024-08-28 06:53:31 | 82 | 1 | | 5 | 20240826.180000 | create category table | SQL | V20240826.180000__create_category_table.sql | 1347572117 | kazuhira | 2024-08-28 06:59:20 | 219 | 1 | +----------------+-----------------+-----------------------+------+---------------------------------------------+------------+--------------+---------------------+----------------+---------+ 5 rows in set (0.0005 sec)
古い日付のマイグレーションのinstalled_rankが最新になっているものの、適用されているようです。
テーブルにもアクセスできます。
MySQL localhost:3306 ssl practice SQL > select * from category; Empty set (0.0018 sec)
というわけで、Out Of Orderの効果を確認できました。
おわりに
Flywayのマイグレーションの管理ということで、バージョンの付け方やマイグレーションの配置先などをいろいろ書いてみました。
このやり方で微妙に思うところはあったりもするのですが、いろいろ考えてこの付近が妥協点かなとも思ったり。
参考になればということもありますが、自分はこのあたりをベースに考えたいと思います。