データベースマイグレーション管理ツール dbmate
目的
- 未公開記事の発掘
- upとdownを同じファイルに書けるのは無駄なくてよさそう
amacneil/dbmate でデータベースマイグレーションを始めるときのガイドです。
依存関係は少ないし、凝った動作もしないのでなんかよさそう。
仕組み
- 管理対象データベースに
schema_migrations
というテーブルを作成し、マイグレーションスクリプトの適用状況を追跡します - データベースのローカルオブジェクト (テーブルやビューやシーケンスなど) を管理します
- データベースのグローバルオブジェクト (ユーザーや権限など) は管理しません
- データベーススキーマをダンプするときはデータベースソフトウェア固有のコマンドを利用します
- MySQL -
mysqldump
- PostgreSQL -
pg_dump
- MySQL -
準備
amacneil/dbmate のインストール
Go が入ってるなら go install
するだけ。
そうでなければリリースアセットから対象OSの実行可能ファイルをダウンロードします。
go install github.com/amacneil/dbmate@latest
サンプルリポジトリのダウンロード
Sakila データベースを MySQL (8.0.21) と PostgreSQL (13) のコンテナにロードする docker-compose.yml
ファイルを用意しました。
dbmate は 8.x 以上の MySQL に対応しています (5.x には対応してません)
$ git clone https://bitbucket.org/yujiorama/db-migration-base-202009 $ cd db-migration-base-202009 $ docker-compose up -d $ docker-compose ps Name Command State Ports ------------------------------------------------------------------------------------------------- mysql-demo_mysql_1 docker-entrypoint.sh mysqld Up 0.0.0.0:3306->3306/tcp, 33060/tcp mysql-demo_postgres_1 docker-entrypoint.sh postgres Up 0.0.0.0:5432->5432/tcp
後始末するときはこちらを。
# ボリュームも一緒に削除します docker-compose down -v
ガイド
1 新しい DDL/DML を用意する
new
サブコマンドを実行すると、新しい DDL/DML を記述する SQL ファイルを作成します。
引数は SQL ファイル名の一部になります。
$ dbmate --url "mysql://user:password@host:port/db" new create-todo-table Creating migration: db/migrations/yyyymmddHHMMSS_create-todo-table.sql
SQL ファイルはコメントで 2 つの部分に分かれています。
-- migrate:up -- migrate:down
migrate:up
にはup
サブコマンドで実行する SQL を記述しますmigrate:down
にはrollback
サブコマンドで実行する SQL を記述します- それぞれの部分には何行でも SQL を記述できます
ファイルを作成するディレクトリ名は --migrations-dir
オプション、あるいは、環境変数 DBMATE_MIGRATIONS_DIR
で指定できます。
環境別にディレクトリを分けるやり方はたぶん事故ります。
ブランチを別にするか、リポジトリを別にしたほうがいいでしょう。
$ dbmate --url "mysql://user:password@host:port/db" --migrations-dir mydb/migrations new create-todo-table Creating migration: mydb/migrations/20200928093003_create-todo-table.sql $ DBMATE_MIGRATIONS_DIR=otherdb/migrations dbmate --url "mysql://user:password@host:port/db" new create-todo-table Creating migration: otherdb/migrations/20200928093003_create-todo-table.sql
2 用意した DDL/DML を適用する
up
サブコマンドは SQL ファイルの migrate:up
部分を実行できます。
schema_migrations
テーブルを検索して適用済みかどうかを判断するようです。
$ dbmate --url mysql://user:pass1word@minikube:3306/sakila up
Applying: 20200928090841_create-todo-table.sql
status
サブコマンドを実行すると適用済みかどうかを確認できます。
$ dbmate --url mysql://user:pass1word@minikube:3306/sakila status [X] 20200928090841_create-todo-table.sql Applied: 1 Pending: 0
なお、複数 Pending
がある状態で up
すると順番に実行していきます。
$ dbmate --url mysql://user:pass1word@minikube:3306/sakila up Applying: 20200928093936_create-todo-table.sql Applying: 20200928094214_create-todo-table.sql $ dbmate --url mysql://user:pass1word@minikube:3306/sakila status [X] 20200928090841_create-todo-table.sql [X] 20200928093936_create-todo-table.sql [X] 20200928094214_create-todo-table.sql Applied: 3 Pending: 0
3 適用した DDL/DML をロールバックする
rollback
サブコマンドは SQL ファイルの migrate:down
部分を実行できます。
最後に適用した SQL ファイル、つまり、最後に Applied
になった SQL ファイルを対象にするようです。
$ dbmate --url mysql://user:pass1word@minikube:3306/sakila status [X] 20200928090841_create-todo-table.sql [X] 20200928093936_create-todo-table.sql [ ] 20200928094214_create-todo-table.sql Applied: 2 Pending: 1 $ dbmate --url mysql://user:pass1word@minikube:3306/sakila rollback Rolling back: 20200928093936_create-todo-table.sql $ dbmate --url mysql://user:pass1word@minikube:3306/sakila status [X] 20200928090841_create-todo-table.sql [ ] 20200928093936_create-todo-table.sql [ ] 20200928094214_create-todo-table.sql Applied: 1 Pending: 2
なお、 migrate:down
の部分に構文エラーがあると実行時エラーになります。
たぶん実行時エラーの場合もですが、ロールバックしたことにはなりません。
$ dbmate --url mysql://user:pass1word@minikube:3306/sakila status [X] 20200928090841_create-todo-table.sql [X] 20200928093936_create-todo-table.sql [X] 20200928094214_create-todo-table.sql Applied: 3 Pending: 0 $ echo '1;' >> db/migrations/20200928094214_create-todo-table.sql $ dbmate --url mysql://user:pass1word@minikube:3306/sakila rollback Rolling back: 20200928094214_create-todo-table.sql Error: Error 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '1' at line 3 $ dbmate --url mysql://user:pass1word@minikube:3306/sakila status [X] 20200928090841_create-todo-table.sql [X] 20200928093936_create-todo-table.sql [X] 20200928094214_create-todo-table.sql Applied: 3 Pending: 0
4 schema_migrations
テーブル
create
や up
や rollback
を最初に実行するとき、接続先URLで指定したデータベースへ作成します。
$ mysql --user user -p -h minikube sakila Enter password: ********* Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 33 Server version: 8.0.21 MySQL Community Server - GPL Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> desc schema_migrations; +---------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +---------+--------------+------+-----+---------+-------+ | version | varchar(255) | NO | PRI | NULL | | +---------+--------------+------+-----+---------+-------+ 1 row in set (0.00 sec) mysql> select * from schema_migrations; +----------------+ | version | +----------------+ | 20200928090841 | | 20200928093936 | | 20200928094214 | +----------------+ 3 rows in set (0.00 sec)