FlywayによるDBマイグレーション

◆ Live配信スケジュール ◆
サイオステクノロジーでは、Microsoft MVPの武井による「わかりみの深いシリーズ」など、定期的なLive配信を行っています。
⇒ 詳細スケジュールはこちらから
⇒ 見逃してしまった方はYoutubeチャンネルをご覧ください
VSCode Dev Containersで楽々開発環境構築祭り〜Python/Reactなどなど〜
Visual Studio Codeの拡張機能であるDev Containersを使ってReactとかPythonとかSpring Bootとかの開発環境をラクチンで構築する方法を紹介するイベントです。
https://tech-lab.connpass.com/event/311864/

みなさん、こんにちは。サイオステクノロジー武井です。DBマイグレーションツールflywayを触る機会があったので、利用用途や利用方法をブログに残したいと思います。

Flywayとは?

DBマイグレーションツールです。スキーマの作成や変更などの処理をリリースするアプリの中に埋め込むことができます。

Flywayが必要になる理由

ID・姓・名の3つのフィールドを持つusersという名前のテーブルがあるとします。DDLは以下のとおりです。

CREATE TABLE users (
   id INT AUTO_INCREMENT PRIMARY KEY,
   last_name VARCHAR(100) NOT NULL,
   first_name VARCHAR(100) NOT NULL
);

まず、このテーブルを管理するアプリをリリースできたとします。

そして、次に改修要件として、メールアドレスを格納するフィールドmailを追加する必要がでてきて、Aさんはその開発担当者にアサインされました。

Aさんは、テーブルを変更するために、Aさん専用の開発環境用データベースに以下のDDLを適用し、開発を行い、無事完了させました。

ALTER TABLE users ADD mail VARCHAR(255);

しかし、Aさんは上記のスキーマ変更のことを誰にも共有せず、改修したソースだけをリポジトリにPushしました。

Bさんは、AさんがリポジトリにPushしたコードをPullしましたが、当然動きません。Bさん専用の開発環境用データベースには上記のDDLが適用されていない、つまりmailフィールドがないからです。

このような事態を防ぐには、「アプリケーションのバージョンとデータベース構成のバージョンを一致させること」が必須となるのですが、それを実現するのがflywayです。

やってみる

先程挙げた以下のユースケースをflywayを使って実際にやってみたいと思います。

  1. usersテーブルを作成し、そのテーブルを管理するアプリを開発する。
  2. usersテーブルにmailフィールドを追加し、mailフィールドを取得できるようアプリを改修する。

usersテーブルを作成し、そのテーブルを管理するアプリを開発する

バージョン管理にgradle、データベースにMySQLを使うとして、gradleに以下の設定を追加します。

dependencies {
  runtimeOnly 'org.flywaydb:flyway-mysql' // 追加
  runtimeOnly 'com.mysql:mysql-connector-j' // 追加
  ...
}

 

次にapplication.ymlに以下の内容を追記します。

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/db # JDBC接続文字列
    username: user // データベース接続ユーザー
    password: password // データベース接続パスワード
    driver-class-name: com.mysql.cj.jdbc.Driver # ドライバークラス名
flyway:
  enabled: true # flyawyを有効にする

 

データベースに適用させたいSQLを定義します。V1__create_table1.sqlという名前のファイルを作成し、以下の内容を追記します。

CREATE TABLE users (
   id INT AUTO_INCREMENT PRIMARY KEY,
   last_name VARCHAR(100) NOT NULL,
   first_name VARCHAR(100) NOT NULL
);

このファイル名は以下の規則によって命名されています。

V[バージョン番号]__[説明].sql

[バージョン番号]はこの番号が若い順から適用されていきます。仮にV1__create_table1.sqlとV2__alter_table1.sqlというファイル名があった場合、V1__create_table1.sql→V2__alter_table1.sqlの順にSQLが実行されます。

[説明]はこのSQL文がどういったものなのかを表す説明になります。日本語OKです。

先程作成したV1__create_table1.sqlを以下のディレクトリに配置します。デフォルトではクラスパスの通っているディレクトリ配下にdb/migrationというディレクトリを作成し、そこにマイグレーションしたいSQLファイルを配置します。

main
└── resources
    └── db
        └── migration
            └── V1__create_table1.sql

usersテーブルを操作するアプリを開発します。

そして以下のコマンドを実行します。

$ ./gradlew bootRun

すると以下のテーブルが作成されているはずです。

  • flyway_schema_history
  • users

flyway_schema_historyはマイグレーション情報を管理するテーブルです。どのマイグレーションがすでに適用されたか、またそれらのマイグレーションがいつ適用されたかを追跡するために使用します。

そしてこれらのファイルをリポジトリにPushします。

usersテーブルにmailフィールドを追加し、mailフィールドを取得できるようアプリを改修する

usersテーブルにmailフィールドを追加するためのSQLを定義します。V2__alter_table1.sqlという名前のファイルを作成し、以下の内容を追記します。

ALTER TABLE users ADD mail VARCHAR(255)

 

先程作成したV2__alter_table1.sqlを以下のディレクトリに配置します。

main
└── resources
    └── db
        └── migration
            ├── V1__create_table1.sql
            └── V2__alter_table1.sql

 

usersテーブルのmailフィールドを取得するアプリを開発します。

そして以下のコマンドを実行します。

$ ./gradlew bootRun

するとusersテーブルにmailフィールドが追加されているはずです。

そしてこれらのファイルをリポジトリにPushします。

つまりアプリを実行すると同時に、事前に定義したスキーマ情報(db/migration配下に作成されたSQLファイル)に従い、flywayがテーブルを作成してくれます。

アプリのリリースとデータベースの構成が同時に行われるので、先に説明したようにアプリの改修だけ反映されて、それに伴うスキーマの構成が未反映という状態はなくなります。

便利ですね。

既にテーブルが存在する場合

既にテーブルが存在している場合のマイグレーションの方法を説明します。

つまり先の例で言えば、既にusersテーブルは作成されているけれど、mailフィールドが追加されていない状態からflywayを利用したい場合です。

このような場合はベースラインバージョンというものを指定します。つまり、どのSQLから適用させたいかを指定するのです。今回の場合は、V1__create_table1.sql(バージョン1)はスキップして、V2__alter_table1.sql(バージョン2)から適用させたいですよね。

main
└── resources
    └── db
        └── migration
            ├── V1__create_table1.sql ← これはスキップしたい
            └── V2__alter_table1.sql ← ここから適用させたい

 

そのためには、application.ymlにbaseline-versionとbaseline-on-migrateを追記します。

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/db # JDBC接続文字列
    username: user // データベース接続ユーザー
    password: password // データベース接続パスワード
    driver-class-name: com.mysql.cj.jdbc.Driver # ドライバークラス名
flyway:
  baseline-version: 1 # バージョン1をスキップする場合、ベースラインバージョンは1となる
  enabled: true # flyawyを有効にする
  baseline-on-migrate: true # 既にテーブルが存在するときにマイグレーションする場合はtrueとする

 

そして以下のコマンドを実行します。

$ ./gradlew bootRun

 

flyway_schema_historyテーブルが作成され、usersテーブルにmailフィールドが追加されているはずです。

まとめ

flywayいい感じですよね。つかってみようかなぁ。

アバター画像
About 武井 宜行 266 Articles
Microsoft MVP for Azure🌟「最新の技術を楽しくわかりやすく」をモットーにブログtech-lab.sios.jp)で情報を発信🎤得意分野はAzureによるクラウドネイティブな開発(Javaなど)💻「世界一わかりみの深いクラウドネイティブ on Azure」の動画を配信中📹 https://t.co/OMaJYb3pRN
ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

0人がこの投稿は役に立ったと言っています。


ご覧いただきありがとうございます。
ブログの最新情報はSNSでも発信しております。
ぜひTwitterのフォロー&Facebookページにいいねをお願い致します!



>> 雑誌等の執筆依頼を受付しております。
   ご希望の方はお気軽にお問い合わせください!

Be the first to comment

Leave a Reply

Your email address will not be published.


*


質問はこちら 閉じる