はじめに
フレームワーク無しの環境で開発をしている場合、手動でテーブル追加などの運用をしている現場も少なくないでしょう。手動運用をしていると
- いつテーブル・カラム追加されたか分からない
- 本番環境、複数の開発者の開発環境で、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}
を変更してください。
<?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の場合ですと、以下の書式で設定できます。(好きな方を選べということだろうが、一つにしてほしい・・)
development:
driver: mymysql
open: tcp:localhost:3306*#{dbname}/#{username}/#{password}
マイグレーション
それでは、各ツールのマイグレーション機能を見ていきましょう。
phpmig
generateコマンドを利用して、マイグレーションファイルを作成します。
$ vendor/bin/phpmig generate AddPosts
+f ./migrations/20170610153605_AddPosts.php
up/downの関数が定義された雛形が作成されます。
<?php
use Phpmig\Migration\Migration;
class AddPosts extends Migration
{
/**
* Do the migration
*/
public function up()
{
}
/**
* Undo the migration
*/
public function down()
{
}
}
ドキュメントのこちらを参考に、以下のようにSQLを記述します。
<?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によると、この仕様には、新しい記述や文法を学ぶ必要がなく、簡単だからとのことです。
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が、一番良かったので今後使っていきたいという結論になりました。