マルチリソース、マルチテナントに対応したDBマイグレーションツール「solidbase」1.0.0をリリースしました

Javaベースのデータベースマイグレーションツールsolidbase 1.0.0をリリースしました。

github.com

これは元々GitBucketで使用するために開発したものです。GitBucketではこれまで独自に実装した簡易的なマイグレーションシステムを使用していたのですが、外部データベースの対応やプラグインシステムの導入などに伴ってより汎用的なマイグレーションツールへの移行を検討していました。

Javaで利用可能なデータベースマイグレーションツールにはFlywayLiquibaseなどがありますが、以下のような要件をすべて満たすものがありませんでした。

  • データベースだけでなく他のリソースも扱うことができる(任意のマイグレーション処理を実行したい)
  • 1つの定義で異なるDBに対応する(デフォルトのH2だけでなくMySQLPostgreSQLなどにも1つの定義で対応したい)
  • マルチテナントに対応する(コアだけでなくプラグインからもマイグレーションシステムを利用したい)

そこで、抽象的な定義ファイルから各データベース向けのDDLを生成することのできるLiquibase*1をライブラリと使用して独自に開発することにしました。

ここではsolidbaseの使い方を簡単に説明したいと思います。

依存関係を追加する

Mavenであればpom.xmlに以下のような依存関係を追加します。他のビルドツールを使っている場合は適宜ツールに応じた設定を追加してください。

<repositories>
  <repository>
    <id>amateras-snapshot</id>
    <name>Project Amateras Maven2 Repository</name>
    <url>http://amateras.sourceforge.jp/mvn/</url>
  </repository>
</repositories>

<dependencies>
  <dependency>
    <groupId>io.github.gitbucket</groupId>
    <artifactId>solidbase</artifactId>
    <version>1.0.0</version>
  </dependency>
</dependencies>

そういえばGitBucketのアーティファクトIDでsonatypeに申請済みなのでsolidbaseもMaven Centralから使えるようにしたほうがいいですね…。*2

XMLファイルを作る

まず、以下のようなXMLファイルをクラスパス内に作成しておきます。

<changeSet>
  <createTable tableName="person">
      <column name="id" type="int" autoIncrement="true" primaryKey="true" nullable="false"/>
      <column name="firstname" type="varchar(50)"/>
      <column name="lastname" type="varchar(50)" constraints nullable="false"/>
      <column name="state" type="char(2)"/>
  </createTable>
</changeSet>

基本的にはLiquibaseのXMLファイルと同じですが、1ファイルに1つの<changeSet>を記述する、ネストして記述する必要のあったタグを<column>の属性として記述できる、といった違いがあります。

マイグレーションモジュールを定義する

以下のようなコードでマイグレーションを行うモジュールを定義します

import io.github.gitbucket.solidbase.migration.LiquibaseMigration;
import io.github.gitbucket.solidbase.model.Module;
import io.github.gitbucket.solidbase.model.Version;

Module module = new Module(
  // モジュールのID(マルチテナントの場合、このIDでバージョンが管理されます)
  "test",
  // バージョンの定義(古いものから順に並べます)
  new Version("1.0.0", new LiquibaseMigration("test_1.0.0.xml")),
  new Version("1.0.1", new LiquibaseMigration("test_1.0.1.xml")),
  ...
);

solidbaseではXMLファイルでマイグレーションを行うLiquibaseMigrationの他に、任意のSQLを実行可能なSqlMigration*3が用意されています。また、Migrationクラスを独自に実装することで任意の処理を行うこともできます。以下は1つのバージョンに複数マイグレーションを指定する場合の定義例です。

import io.github.gitbucket.solidbase.migration.LiquibaseMigration;
import io.github.gitbucket.solidbase.migration.Migration;

new Version("1.0.0",
  // まずデータベースのマイグレーションを行う
  new LiquibaseMigration("test_1.0.0.xml"),
  // 次に任意の処理を行う
  new Migration(){
    @Override
    public void migrate(String moduleId, String version, Map<String, Object> context) throws Exception {
      ...
    }
  }
);

マイグレーションを実行する

実際にマイグレーションを行うには以下のようにします。

import io.github.gitbucket.solidbase.SolidBase;
import java.sql.DriverManager;
import liquibase.database.core.H2Database;

Solidbase solidbase = new Solidbase();

solidbase.migrate(
  DriverManager.getConnection("jdbc:h2:mem:test", "sa", "sa"),
  Thread.currentThread().getContextClassLoader(),
  new H2Database(), // データベースに応じたクラスを指定
  module // 定義したマイグレーションモジュールを指定
);

そんなわけでさほど大したものではないのですが、GitBucketのように多様なリソースやデータベースをサポートしなくてはならないパッケージ製品では使い道があるのではないかと思います。

また、GitBucketでは4.0以降、マイグレーションシステムがsolidbaseに移行するためプラグインでデータベースのマイグレーションが必要な場合はsolidbaseを使うことになります。既存のプラグインをGitBucket 4.0以降で動作させる場合もsolidbaseへの移行が必要になりますのでご注意ください。

*1:とはいえデータベース間の違いを完全に吸収してくれるわけではなく、XMLの記述の仕方に気をつけないといけないケースもあります。

*2:同じくGitBucketのorganizationで開発しているmarkedjはすでにMaven Centralに公開済み。

*3:データベースごとに実行するSQLファイルを変えることも可能です。