Published on

Flywayメモ

Authors
  • avatar
    Name
    Kikusan
    Twitter

Flywayとは

DBマイグレーションツール。JVMで動作する。

DB

今回はPostgresqlを使用する。 docker-composeで用意。

version: '3'

services:
  postgres:
    image: postgres:latest
    restart: always
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: sample
      TZ: "Asia/Tokyo"
    ports:
      - 5432:5432
    volumes:
      - ./data:/var/lib/postgresql/data
docker-compose up -d

Gradleでの使用

GUI,CLI,Maven,Gradle,Dockerなどで使用できる。

https://documentation.red-gate.com/fd/gradle-task-184127407.html

  • build.gradle
plugins {
    id "java"
    id "org.flywaydb.flyway" version "9.21.1"
}

group 'work.sehippocampus.flyway'
version '1.0-SNAPSHOT'

repositories {
    mavenCentral()
}

dependencies {
    runtimeOnly "org.postgresql:postgresql:42.6.0"
}

flyway {
    driver = 'org.postgresql.Driver'
    url = 'jdbc:postgresql://localhost:5432/sample'
    user = 'postgres'
    password = 'postgres'
    schemas = ['public']
}

flyway migrate

なにもmigrationファイルを用意しないで実行してみる。

gradle flywayMigrate -i

> Task :flywayMigrate
Caching disabled for task ':flywayMigrate' because:
  Build cache is disabled
Task ':flywayMigrate' is not up-to-date because:
  Task has not declared any outputs despite executing actions.
Database: jdbc:postgresql://localhost:5432/sample (PostgreSQL 13.3)
Successfully validated 0 migrations (execution time 00:00.008s)
No migrations found. Are your locations set up correctly?
Current version of schema "public": << Empty Schema >>
Schema "public" is up to date. No migration necessary.
:flywayMigrate (Thread[Execution worker for ':',5,main]) completed. Took 0.134 secs.

この時点でhistoryテーブルが作成されている。


migrationファイルを作成して実行してみる。
デフォルトでclasspathのdb/migrationが配置フォルダ。

  • src/main/resources/db/migration/V1_0_0__Create_person_table.sql
CREATE TABLE person (
    id serial PRIMARY KEY,
    name varchar(100) NOT NULL
);
> Task :flywayMigrate
Caching disabled for task ':flywayMigrate' because:
  Build cache is disabled
Task ':flywayMigrate' is not up-to-date because:
  Task has not declared any outputs despite executing actions.
Database: jdbc:postgresql://localhost:5432/sample (PostgreSQL 13.3)
Successfully validated 1 migration (execution time 00:00.010s)
Current version of schema "public": << Empty Schema >>
Migrating schema "public" to version "1.0.0 - Create person table"
Successfully applied 1 migration to schema "public", now at version v1.0.0 (execution time 00:00.029s)
:flywayMigrate (Thread[Execution worker for ':',5,main]) completed. Took 0.189 secs.

ここで実行されたversionが記録される。

もう一度実行するとversionが記録されているため、何も起きない。

> Task :flywayMigrate
Caching disabled for task ':flywayMigrate' because:
  Build cache is disabled
Task ':flywayMigrate' is not up-to-date because:
  Task has not declared any outputs despite executing actions.
Database: jdbc:postgresql://localhost:5432/sample (PostgreSQL 13.3)
Successfully validated 1 migration (execution time 00:00.009s)
Current version of schema "public": 1.0.0
Schema "public" is up to date. No migration necessary.
:flywayMigrate (Thread[Execution worker for ':',5,main]) completed. Took 0.136 secs.

次のversionで、sqlを間違えてみる。

  • src/main/resources/db/migration/V1_0_1__Insert_person.sql
INSERT INTO person (name)
VALUES ('John Doe');

INSERT INTO person (name)
VALUE ('Jane Smith');

怒られる。

ERROR: syntax error at or near "VALUE"
  位置: 27

直して実行するとうまくいく。

と思ったがserialのシーケンスは戻らない。 トランザクションはサポートされるが、トランザクション外のものはだめだった。


デフォルトではトランザクション外のものを混ぜようとしたらFlywayには怒られた。

Detected both transactional and non-transactional statements within the same migration (even though mixed is false).

同じversionでファイルを分けることも不可。

Found more than one migration with version 1.0.2

トランザクション外のSQLだけで実行してみるとやはり戻りはしない。


一度DBも初期化してすべてのversionが実行されるようにする。

  • src/main/resources/db/migration/V1_0_2__Insert_person.sql
CREATE TABLE person2 (
    id serial PRIMARY KEY,
    name varchar(100) NOT NULL
);

INSERT INTO person (name)
VALUES ('Alice Johnson');

INSERT INTO person (name)
VALUE ('Bob Williams');

失敗するversionまではコミットされる。


一度実行したマイグレーションファイルの中身を変えるとchecksumが合わなくなるため失敗する。

Validate failed: Migrations have failed validation
Migration checksum mismatch for migration version 1.0.2
-> Applied to database : 2126117717
-> Resolved locally    : -87275235
Either revert the changes to the migration, or run repair to update the schema history.
Need more flexibility with validation rules? Learn more: https://rd.gt/3AbJUZE

flyway info

マイグレーションの情報を見られる。

例えば実行時の失敗を起こしてみる。

  • src/main/resources/db/migration/V1_0_3__Fail.sql
CREATE TABLE person (
    id serial PRIMARY KEY,
    name varchar(100) NOT NULL
);
ERROR: relation "person" already exists
gradle flywayInfo

> Task :flywayInfo
Schema version: 1.0.2
+-----------+---------+---------------------+------+---------------------+---------+----------+
| Category  | Version | Description         | Type | Installed On        | State   | Undoable |
+-----------+---------+---------------------+------+---------------------+---------+----------+
| Versioned | 1.0.0   | Create person table | SQL  | 2023-08-12 00:49:12 | Success | No       |
| Versioned | 1.0.1   | Insert person       | SQL  | 2023-08-12 00:49:12 | Success | No       |
| Versioned | 1.0.2   | Insert person       | SQL  | 2023-08-12 00:49:12 | Success | No       |
| Versioned | 1.0.3   | Fail                | SQL  |                     | Pending | No       |
+-----------+---------+---------------------+------+---------------------+---------+----------+

flyway clean

Flywayで使用しているスキーマの情報をすべてドロップする。
マイグレーションしているかは関係なく、独自実行したSQLの分も全てDropされる。

flyway {
    // ...
    cleanDisabled = false
}

flyway baseline

なにもマイグレーションしていない時に限り、現状のDBをversion1として記録できる。

flyway repair

Flywayのhistoryテーブルに存在しているversionについて、
checksumを現状のマイグレーションファイルに合わせて修正する。 マイグレーションは実行されない。
実行されたマイグレーションの内容は書き換えられるが、環境差分になってしまうし前進処理したほうが無難。

flyway Validate

historyテーブルとマイグレーションファイルの整合性を検証する。 名前やchecksumが違うとエラーになる。

flyway undo

最後のマイグレーションを戻せるらしい。
Teamsプランしかできない。