28
33

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2017-06-11

はじめに

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

  • いつテーブル・カラム追加されたか分からない
  • 本番環境、複数の開発者の開発環境で、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が、一番良かったので今後使っていきたいという結論になりました。

28
33
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
28
33

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?