post Image
DBマイグレーションツールを比較した phpmig, migrate, goose

はじめに

フレームワーク無しの環境で開発をしている場合、手動でテーブル追加などの運用をしている現場も少なくないでしょう。手動運用をしていると

  • いつテーブル・カラム追加されたか分からない
  • 本番環境、複数の開発者の開発環境で、DB環境が一致していない

などの問題が起きます。これらは、マイグレーションツールを導入することで解決します。
今回は、フレームワークに依存しないDBマイグレーションツール3つを比較・検証します。

ツール

以下の3つを比較します。

ツール名 必要環境
phpmig PHP 5.3以上, Composer
migrate Go
goose Go

前提

  • Mac OSX Yosemite
  • MySQL 5.6.36

検証

インストール

インストールはどのツールも簡単です。

phpmig

# マイグレーションツールphpmig本体
$ composer require davedevelopment/phpmig

# DIコンテナツール
$ composer require pimple/pimple

migrate

$ curl -L https://github.com/mattes/migrate/releases/download/v3.0.1/migrate.darwin-amd64.tar.gz | tar xvz
$ mv migrate.darwin-amd64 /usr/local/bin/migrate

goose

$ go get bitbucket.org/liamstask/goose/cmd/goose

初期設定

phpmig

initコマンドを実行することで、マイグレーションファイルを配備するディレクトリとDB接続情報を保持する設定ファイルが作成されます。

$ vendor/bin/phpmig init
+d ./migrations Place your migration files in here
+f ./phpmig.php Create services in here

ローカルのMySQLに接続するため、phpmig.phpファイルを修正します。#{dbname},#{username}, #{password}を変更してください。

phpmig.php
<?php

# phpmig.php

use Phpmig\Adapter;
use Pimple\Container;

$container = new Container();

$container['db'] = function () {
    $dbh = new PDO('mysql:dbname=#{dbname};host=127.0.0.1','#{username}','#{password}');
    $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    return $dbh;
};

$container['phpmig.adapter'] = function ($c) {
    return new Adapter\PDO\Sql($c['db'], 'migrations');
};

$container['phpmig.migrations_path'] = __DIR__ . DIRECTORY_SEPARATOR . 'migrations';

return $container;

statusコマンドを実行して、以下が表示されれば、設定完了です。

$ vendor/bin/phpmig status

 Status   Migration ID    Migration Name
-----------------------------------------

migrate

DB接続設定を、JSONやYAMLファイルから読み込むことができるようですが、migrate組み込みの機能ではないので、使いづらい印象です。

goose

DB接続設定ファイルの雛形をコピーしてきますが、初期値がPostgreSQL用になっているため、MySQL用に修正する必要があります。しかし残念なことに、ドキュメントにはMySQLの設定方法は解説されていません。

$ mkdir db
$ cp /Users/hypermkt/src/bitbucket.org/liamstask/goose/db-sample/
dbconf.yml db/

ソースコードの lib/goose/dbconf.go によると、driverには、mysqlとmymysqlの2つが設定できることが分かります。特に理由は無いですが、mymysqlの場合ですと、以下の書式で設定できます。(好きな方を選べということだろうが、一つにしてほしい・・)

db/dbconf.yml
development:
    driver: mymysql
    open: tcp:localhost:3306*#{dbname}/#{username}/#{password}

マイグレーション

それでは、各ツールのマイグレーション機能を見ていきましょう。

phpmig

generateコマンドを利用して、マイグレーションファイルを作成します。

$ vendor/bin/phpmig generate AddPosts
+f ./migrations/20170610153605_AddPosts.php

up/downの関数が定義された雛形が作成されます。

./migrations/20170610153605_AddPosts.php
<?php

use Phpmig\Migration\Migration;

class AddPosts extends Migration
{
    /**
     * Do the migration
     */
    public function up()
    {
    }

    /**
     * Undo the migration
     */
    public function down()
    {
    }
}

ドキュメントのこちらを参考に、以下のようにSQLを記述します。

./migrations/20170610153605_AddPosts.php
<?php

use Phpmig\Migration\Migration;

class AddPosts extends Migration
{
    /**
     * Do the migration
     */
    public function up()
    {
        $sql = "
            CREATE TABLE posts(
                `id` integer NOT NULL AUTO_INCREMENT,
                `content` TEXT NOT NULL,
                `created_at` datetime DEFAULT CURRENT_TIMESTAMP(),
                PRIMARY KEY (`id`)
            );
";
        $container = $this->getContainer(); 
        $container['db']->query($sql);
    }

    /**
     * Undo the migration
     */
    public function down()
    {
        $sql = "DROP TABLE posts;";
        $container = $this->getContainer(); 
        $container['db']->query($sql);
    }
}

statusコマンドで、バージョン = Migration IDを確認します。

$ vendor/bin/phpmig status

 Status   Migration ID    Migration Name
-----------------------------------------
   down  20170610153605  AddPosts

upコマンドの引数に、先程調べたバージョンを指定します。-vvvは、より多くの情報を表示するデバッグモードにつき、無くても動作します。これでテーブル作成が実行できます。

$ vendor/bin/phpmig up -vvv 20170610153605
 == 20170610153605 AddPosts migrating
 == 20170610153605 AddPosts migrated 0.0315s

migrate

マイグレーションファイルは、以下の書式で作成します。
#{タイムスタンプ又は連番}_#{名前}.#{up又はdown}.sql

こちらのFAQによると、この仕様には、新しい記述や文法を学ぶ必要がなく、簡単だからとのことです。

1_Create_Posts.up.sql
CREATE TABLE posts(
  `id` integer NOT NULL AUTO_INCREMENT,
  `content` TEXT NOT NULL,
  `created_at` datetime DEFAULT CURRENT_TIMESTAMP(),
  PRIMARY KEY (`id`)
);

以下オプションを指定することで、テーブルの作成が実行されます。

  • -verbose ログを出力
  • -database データベース接続設定を指定
  • -path マイグレーションファイルのパスを指定
  • up upマイグレーションを実行
$ migrate -verbose -database  'mysql://#{username}:#{password}@tcp(127.0.0.1:3306)/#{dbname}' -path ./ up
2017/06/11 00:54:13 Start buffering 1/u Create_Posts
2017/06/11 00:54:13 Read and execute 1/u Create_Posts
2017/06/11 00:54:13 Finished 1/u Create_Posts (read 20.324089ms, ran 15.589152ms)
2017/06/11 00:54:13 Finished after 37.83673ms
2017/06/11 00:54:13 Closing source and database

migrateの特徴としては、forceコマンドを利用することで、指定バージョンまでスキップさせることができます。その際のマイグレーションは実行されます。例えば、以下2つのマイグレーションファイルがあったとし、既存DBではpostsテーブルが作成済みとします。

  • 1_Create_Posts.up.sql
    • postsテーブルを作成する
  • 2_Create_Users.up.sql
    • usersテーブルを作成する

早速試します。forceコマンドにオプション1を渡すことで、バージョンを1に変更にし、1は実行済みの体としてスキップできます。

$ migrate -verbose -database  'mysql://root:@tcp(127.0.0.1:3306)/migration_migrate' -path ./ force 1
2017/06/12 00:09:22 Finished after 18.110456ms
2017/06/12 00:09:22 Closing source and database

versionコマンドで確認した所、1になりました。

 migrate -verbose -database  'mysql://root:@tcp(127.0.0.1:3306)/migration_migrate' -path ./ version
2017/06/12 00:09:34 1
2017/06/12 00:09:34 Closing source and database

その状態で、upコマンドを実行すると、2番だけが実行されます。

$ migrate -verbose -database  'mysql://root:@tcp(127.0.0.1:3306)/migration_migrate' -path ./ up
2017/06/12 00:09:38 Start buffering 2/u Create_Users
2017/06/12 00:09:38 Read and execute 2/u Create_Users
2017/06/12 00:09:38 Finished 2/u Create_Users (read 21.020083ms, ran 15.266951ms)
2017/06/12 00:09:38 Finished after 37.777123ms
2017/06/12 00:09:38 Closing source and database

goose

craeteコマンドにsqlオプションを渡すことで、SQLファイルでマイグレーションファイルが作成されます。

$ goose create CreatePosts sql
goose: created #{省略}/db/migrations/20170611012402_CreatePosts.sql

作成されたマイグレーションファイルの、Up/Downの箇所に各々のSQL文を記述します。


-- +goose Up
-- SQL in section 'Up' is executed when this migration is applied

CREATE TABLE posts(
  `id` integer NOT NULL AUTO_INCREMENT,
  `content` TEXT NOT NULL,
  `created_at` datetime DEFAULT CURRENT_TIMESTAMP(),
  PRIMARY KEY (`id`)
);

-- +goose Down
-- SQL section 'Down' is executed when this migration is rolled back

DROP TABLE posts;

upコマンドを指定することで、テーブル作成が実行されます。

$ goose up
goose: migrating db environment 'development', current version: 0, target: 20170611012402
OK    20170611012402_CreatePosts.sql

まとめ

各ツールを3点(1:悪い/難しい 2:普通 3:良い/簡単)で評価してみます。

phpmig migrate goose
ドキュメントの充実性 3 2 2
インストール難易度 3 3 3
学習コスト 1 3 3
機能性 2 2 2
将来性 3 3 1
合計 12 13 11

各ツールごとの感想は以下のとおりです。

  • phpmig
    • ドキュメントは一番充実していました。ただコーディング量やpimpleの依存も考慮すると、学習コストがほかと比べて高い印象です。
  • migrate
    • 都度DB設定を記述する手間はありますが、本番環境で導入を考慮すると、一番実用性がありました。
  • goose
    • PostgreSQLのドキュメントは充実していますが、それ以外がコードを見ないと分からないのが不親切でした。また開発も2015年1月を最後に止まっています。機能面では一番シンプルで使い勝手が良かったのですが、残念でした。

100%満足したわけではありませんが、総合的にはmigrateが、一番良かったので今後使っていきたいという結論になりました。


『 Go 』Article List
Category List

Eye Catch Image
Read More

Androidに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

AWSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Bitcoinに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

CentOSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

dockerに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

GitHubに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Goに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Javaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

JavaScriptに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Laravelに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Pythonに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Rubyに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Scalaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Swiftに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Unityに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Vue.jsに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Wordpressに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

機械学習に関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。