マイグレーションツール:dbdeployの使い方

 2013/01/22
このエントリーをはてなブックマークに追加

dbdeployはオープンソースで提供されているマイグレーションツール。 http://code.google.com/p/dbdeploy/ にホストされており、ライセンスはLGPLです。 doctrineやrubyのmigrationとは違ってコードではなく、SQL文で変更情報やロールバック情報を記述する点が特徴です。既にSQL文が書かれたファイルで変更情報を管理している場合は導入が比較的容易と言えます。

インストール

これは簡単です。プロジェクトのページからダウンロードして適当な場所に解凍します。また、今回はApache Ant経由で実行しますので、導入していない場合は先にインストールしておいてください。

wget http://dbdeploy.googlecode.com/files/dbdeploy-dist-3.0M3-distribution.zip
unzip dbdeploy-dist-3.0M3-distribution.zip 

サンプルを動かしてみる

アーカイブにはHSQLDBを利用したサンプルが同梱されています。簡単に実行することができます。ダウンロードしたモジュールのディレクトリに移動してください。そして以下を実行します。

cd example
ant

実行すると以下のように表示されます。

Buildfile: /Users/ryuzee/dev/tmp/dbdeploy_test/dbdeploy-3.0M3/example/build.xml

drop-and-create-database:
    [mkdir] Created dir: /Users/ryuzee/dev/tmp/dbdeploy_test/dbdeploy-3.0M3/example/db

create-changelog-table:
      [sql] Executing resource: /Users/ryuzee/dev/tmp/dbdeploy_test/dbdeploy-3.0M3/scripts/createSchemaVersionTable.hsql.sql
      [sql] 2 of 2 SQL statements executed successfully

clean:

update-database:
 [dbdeploy] dbdeploy 3.0M3
 [dbdeploy] Reading change scripts from directory /Users/ryuzee/dev/tmp/dbdeploy_test/dbdeploy-3.0M3/example…
 [dbdeploy] Changes currently applied to database:
 [dbdeploy] (none)
 [dbdeploy] Scripts available:
 [dbdeploy] 1, 2
 [dbdeploy] To be applied:
 [dbdeploy] 1, 2
 [dbdeploy] Applying #1: 001_create_table.sql…
 [dbdeploy] Applying #2: 002_insert_data.sql…
 [dbdeploy] -> statement 1 of 2…
 [dbdeploy] -> statement 2 of 2…

default:

BUILD SUCCESSFUL
Total time: 2 seconds

この例では1と2のスクリプトが実行されたことが分かります。 具体的にはサンプルのディレクトリにある、001_create_table.sqlと002_insert_data.sqlが実行されており、マイグレーションがどこまで適用されたかを管理するchangelogテーブルが自動で生成されます。 これらのファイルの中身を見てみましょう。

-- Most databases don't apply DDL statements transactionally.
-- Therefore, to recover from failure more easily, only put a single DDL
-- statement in each change script.

CREATE TABLE Test (id INTEGER, data VARCHAR(100));

--//@UNDO

DROP TABLE Test;

覚えておくべき点として、変更内容の下に –//@UNDOを記述し、その下に、適用を戻す処理を記述することです。(別に記述しなくても良いですが、その場合は、dbdeploy経由ではundoできません) このように普段使っているSQLをそのまま使える点がメリットでしょう。

MySQLに対応してみる

上記の例ではHSQLDBを使っていたので、今度はMySQLを使ってみます。 テスト用のディレクトリをアーカイブを解凍したディレクトリの直下にmysql_exampleとして作成します。 また、build.xmlはexampleディレクトリからコピーしておきます。また、SQLを格納するためのディレクトリを作成しておきます。

mkdir mysql_example
cp ../example/build.xml .
mkdir scripts

dbdeployでMySQLに接続するにはJDBCドライバが必要なのでOracleから入手します。 http://dev.mysql.com/downloads/connector/j/ ファイルはzipでもtarでもどちらでも構いません。 ダウンロードし解凍したら、上記のmysql_exampleフォルダ直下にドライバ(mysql-connector-java-5.1.22-bin.jar)をコピーしてください。

次に、build.xmlを修正します。 かなり色々変更しているので、以下をそのままコピペしても構いません。 データベースの接続情報は自分の環境にあわせて変更してください。試しに実行するのであれば、テスト用に新しいデータベースを作るのが良いでしょう。

<?xml version="1.0" encoding="UTF-8"?>

<project name="dbdeploy_mysql_example" default="default">

    <!-- データベースへの接続情報 -->
    <property name="db.driver" value="com.mysql.jdbc.Driver"></property>
    <property name="db.url" value="jdbc:mysql://localhost/dbdeploy_mysql_example"></property>
    <property name="db.user" value="dbuser"></property>
    <property name="db.password" value="hogehoge"></property>

    <path id="mysql.classpath">
        <fileset dir=".">
            <include name="mysql*.jar"></include>
        </fileset>
    </path>

    <path id="dbdeploy.classpath">
        <!-- include the dbdeploy-ant jar -->
        <fileset dir="..">
            <include name="dbdeploy-ant-*.jar"></include>
        </fileset>

        <!-- the dbdeploy task also needs the database driver jar on the classpath -->
        </path><path refid="mysql.classpath"></path>

    <taskdef name="dbdeploy" classname="com.dbdeploy.AntTarget" classpathref="dbdeploy.classpath"></taskdef>

    <target name="default" depends="update-database" description="update database"></target>

    <target name="init" depends="create-changelog-table" description="create changelog table"></target>

    <target name="create-changelog-table">
        <sql driver="${db.driver}" url="${db.url}"
            userid="${db.user}" password="${db.password}" classpathref="mysql.classpath" >
            <fileset file="../scripts/createSchemaVersionTable.mysql.sql"></fileset>
        </sql>
    </target>

    <target name="undo" description="rollback change">
        <sql driver="${db.driver}" url="${db.url}"
             userid="${db.user}" password="${db.password}" classpathref="mysql.classpath" >
             <fileset file="./undo.sql"></fileset>
        </sql>
    </target>

    <target name="update-database" description="update database">

        <!-- use dbdeploy to generate the change script -->
        <dbdeploy driver="${db.driver}" url="${db.url}"
                  userid="${db.user}"
                  password="${db.password}"
                  dir="./scripts"
                  outputfile="output.sql"
                  undoOutputfile="undo.sql"
                  dbms="mysql"></dbdeploy>

        <!-- now apply the changescript to the database -->
        <sql driver="${db.driver}" url="${db.url}"
             userid="${db.user}" password="${db.password}" classpathref="mysql.classpath">
            <fileset file="output.sql"></fileset>
        </sql>

    </target>

    <target name="show-changelog" description="show change log">
        <sql driver="${db.driver}" url="${db.url}"
            userid="${db.user}" password="${db.password}" print="true" classpathref="mysql.classpath">
            select * from change log
        </sql>
    </target>

</project>

この時点では、マイグレーションするスクリプトが1つもないので、新たに用意しましょう。 今回は、元々のサンプルに含まれていたファイルをそのまま利用しますので、以下のようにコピーしてください。

cp ../example/00*.sql ./scripts/

ここまででディレクトリ構成はこうなるはずです。

$ tree ../

├── LICENSE
├── README
├── dbdeploy-ant-3.0M3-sources.jar
├── dbdeploy-ant-3.0M3.jar
├── dbdeploy-cli-3.0M3-sources.jar
├── dbdeploy-cli-3.0M3.jar
├── dbdeploy-core-3.0M3-sources.jar
├── dbdeploy-core-3.0M3.jar
├── example
├── scripts
├── mysql_example
│   ├── build.xml
│   ├── mysql-connector-java-5.1.22-bin.jar
│   ├── scripts
│   │   ├── 001_create_table.sql
│   │   ├── 002_insert_data.sql

これで準備完了なので実行します。 初回実行なので、changelogテーブルを作成します。

ant init

次に、テーブルを作成しましょう。

ant 

これで以下のように表示されるはずです。

Buildfile: /Users/ryuzee/dev/tmp/dbdeploy_test/dbdeploy-3.0M3/mysql_example/build.xml

update-database:
 [dbdeploy] dbdeploy 3.0M3
 [dbdeploy] Reading change scripts from directory /Users/ryuzee/dev/tmp/dbdeploy_test/dbdeploy-3.0M3/mysql_example2/scripts…
 [dbdeploy] Changes currently applied to database:
 [dbdeploy] (none)
 [dbdeploy] Scripts available:
 [dbdeploy] 1, 2
 [dbdeploy] To be applied:
 [dbdeploy] 1, 2
 [dbdeploy] Generating undo scripts…
      [sql] Executing resource: /Users/ryuzee/dev/tmp/dbdeploy_test/dbdeploy-3.0M3/mysql_example2/output.sql
      [sql] 7 of 7 SQL statements executed successfully

default:

BUILD SUCCESSFUL
Total time: 1 second

これでMySQLでもマイグレーションできるようになりました。 上記のサンプルのbuild.xmlでは、他に以下のことをできるようにしています。 コマンドラインで以下を実行してください。

ant -projecthelp

説明が表示されます。

Main targets:

 default              update database                # データベースを更新
 init                 create change log table     #変更履歴テーブル作成
 show-changelog       show change log               #変更情報を表示
 undo                 rollback change                #直近の変更を戻す
 update-database      update database               #データベースを更新
Default target: default

あとは、データベースに変更を加えたい場合は、scriptsディレクトリに数字のファイル名で始まるSQLファイルを作成すればOKです。 なお、数字は既に実行済のものよりも大きい数字でなければいけません。 例えば、既に2000_add_hoge.sql というマイグレーションが実行済の場合に、1999_add_fuga.sqlを追加しようとすると、マイグレーションできません。ブランチのマージ等を考慮すると、番号を10番飛ばしでつけたり、タイムスタンプを使ったりすると良いのではないでしょうか。

 2013/01/22
このエントリーをはてなブックマークに追加