Web開発など

Java, JS, CSS, HTML, Unity, C# のことなどを書いてます。フリーソフトや二次創作の公開もしています。

Java:FlywayでDBマイグレーション

Flyway を使って、PostgreSQL のデータベースをマイグレーションする方法を書いていきます。DBマイグレーションとは、DBのデータを残したまま、テーブル作成やカラム変更などをすることです。

手順1. 依存性の追加

記事「Java共通資源の作成」で作成した pom.xml に、flyway の依存性を追加します。

db-access/pom.xml(追加部分)

    <dependency>
      <groupId>org.flywaydb</groupId>
      <artifactId>flyway-core</artifactId>
      <version>4.2.0</version>
    </dependency>

dependencies タグの下に追加すれば大丈夫です。

手順2. SQLファイルの作成

マイグレーションに使うファイルを作成します。内容はSQLでテーブルを2つ作成する感じです。

db-access/src/main/resources/db/migration/V1__create_tables.sql

create table memo (
  id serial primary key,
  txt varchar(200) not null,
  updated timestamp not null default current_timestamp,
  created timestamp not null default current_timestamp
);

create table person (
  id serial primary key,
  name varchar(100) not null,
  updated timestamp not null default current_timestamp,
  created timestamp not null default current_timestamp
);

ファイルの配置場所と名前は、Flyway の規約 に従っています。ファイルの命名規約は以下の通りです。

V<Version>__<NAME>.sql
  • V:アルファベット大文字の V です。
  • <Version>:数字の 1 や 2_1(アンダースコア区切り)です。SQL ファイルが増えたら、バージョンを上げていきます。
  • __:アンダースコア2つです。<Version> と <Name> を区切ります。
  • <Name>:任意の文字列とされています。

補足1. 次のマイグレーション

2回目以降は、命名規約に従って SQLファイルを用意します。例えば、V2__Alter.sql, V3__Create.sql, ... といったような感じです。

補足2. Flyway の仕様

SQLファイル は、同じスキーマで1回だけ実行されます。Flyway が、スキーマに管理テーブル「schema_version」を作成してコントロールしてくれます。

管理テーブルがなかったり(違う環境・違うスキーマ)、管理テーブルを削除したりすると、全ての SQLファイルが実行されます。

手順3. Mainクラスの作成

Flyway でマイグレーションをして、memo テーブルにデータを追加するクラスを作成します。

db-access/src/main/java/lib/FlywayMain.java

package lib;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

import org.flywaydb.core.Flyway;

import jdbc.base.Driver;

public class FlywayMain {
  public static void main(String[] args)
    throws ClassNotFoundException, SQLException
  {
    //-> マイグレーション
    Flyway flyway = new Flyway();
    flyway.setDataSource(
      "jdbc:postgresql://localhost/test", "neko", "cat"
    );
    flyway.migrate();
    //-> INSERT
    try (Connection con = Driver.connect()) {
      PreparedStatement ps = con.prepareStatement(
        "insert into person (name) values (?)"
      );
      ps.setString(1, "Suzuki Taro");
      int count = ps.executeUpdate();
      System.out.print("INSERT ");
      System.out.println(count);
      ps.close();
    }
  }
}

flyway.migrate(); で、先ほどのSQLを実行してくれます。一度実行されたSQLは、次回のアプリ起動時には実行されないようになります。Flyway が DB にテーブル schema_version を作成して、実行したSQLの情報などを管理してくれます。

手順4. 動作確認

事前に PostgreSQL を起動して、データベース・ユーザを作成しておきます。作成方法は「DB環境の準備」に書いてます。

リンク先のテーブル memo を既に作成している場合は、psql などで drop table memo; を実行して消しておきます。

test=> \d
              リレーションの一覧
 スキーマ |    名前     |     型     | 所有者
----------+-------------+------------+--------
 public   | memo        | テーブル   | neko
 public   | memo_id_seq | シーケンス | neko
(2 行)


test=> drop table memo;
DROP TABLE

それから、上の FlywayMain を実行すると、

SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
INSERT 1

といった文字列が出力されて、INSERTが1件成功してます。上から3行のメッセージ(SLF4J...)は、Flyway が SLF4J を使っている関係で出力されています。

psql でデータを確認してみます。

test=> select id, name from person;
  id |    name
----+-------------
  1 | Suzuki Taro
(1 行)

もう一度 FlywayMain を実行するとデータが2件になります。マイグレーションSQLV1__create_tables.sql)が実行されるのは一度だけです。