この記事ではgolang-migrateを使ってmysqlのデータベースマイグレーションする方法をご紹介します。
golang-migrateでのマイグレーションはこれらのデータベースに対応しています。
- PostgreSQL
- PGX
- Redshift
- Ql
- Cassandra
- SQLite
- SQLite3
- SQLCipher
- MySQL/ MariaDB
- Neo4j
- MongoDB
- CrateDB
- Shell
- Google Cloud Spanner
- CockroachDB
- YugabyteDB
- ClickHouse
- Firebird
- MS SQL Server
dockerで開発環境を作る
まずはdockerでGoとmysqlの開発環境をサクッと作ります。
version: "3"
services:
mysql:
image: mysql:5.7
container_name: mysql
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: blog
MYSQL_USER: docker
MYSQL_PASSWORD: docker
TZ: "Asia/Tokyo"
command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
volumes:
- ./docker/db/data:/var/lib/mysql
- ./docker/db/my.cnf:/etc/mysql/conf.d/my.cnf
- ./docker/db/sql:/docker-entrypoint-initdb.d
ports:
- 3306:3306
phpmyadmin:
container_name: manage-phpmyadmin
image: phpmyadmin/phpmyadmin
environment:
- PMA_ARBITRARY=1
- PMA_HOSTS=manage-mysql
- PMA_USER=root
- PMA_PASSWORD=root
ports:
- 8081:80
blog:
container_name: service
build:
context: ./
image: service:${TAG:-latest}
ports:
- "8082:8080"
tty: true
volumes:
- type: bind
source: ./
target: /app
depends_on:
- mysql
FROM golang:1.19.1-bullseye
WORKDIR /app
COPY ./ /app
EXPOSE 8080
この記事はgolang-migrateの紹介なので、dockerを使った開発環境の設定は必要最小限としています。
必要に応じて設定ファイルを書き換えてください。
dockerの設定ファイルができたら立ち上げます。
$ docker-compose build --no-cache
$ docker-compose up -d
dockerの設定がわからない・できない方はこちらの書籍が参考になります。
golang-migrateを使ってmysqlマイグレーションをする
初めにgolang-migrateをインストールするのでdockerコンテナの中に入ります。
$ docker exec -it servece /bin/bash
次のコマンドでgolang-migrateをインストールします。
今回はmysqlのデータベースを作るので、-tags mysql
を使用します。
$ go install -tags mysql github.com/golang-migrate/migrate/v4/cmd/migrate@latest
go: downloading github.com/golang-migrate/migrate/v4 v4.15.2
go: downloading github.com/golang-migrate/migrate v3.5.4+incompatible
...
go: downloading github.com/hashicorp/errwrap v1.1.0
golang-migrateのインストールが完了したら、マイグレーションをつくます。
まずは次のコマンドでユーザーテーブル用のマイグレーションファイルを作ります。
$ migrate create -ext sql -dir db/migrations -seq create_users
/app/db/migrations/000001_create_users.up.sql
/app/db/migrations/000001_create_users.down.sql
コマンドを実行するとdb/migrationsにこのようなファイルができます。
このファイルにsqlを記述していきます。
- 000001_create_users.up.sql
- 000001_create_users.down.sql
テーブルを作る
テーブルを作るには生成した000001_create_users.up.sqlにsqlでテーブルの定義をします。
-- CreateTable
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(191) NULL,
`username` VARCHAR(191) NULL,
`email` VARCHAR(191) NULL,
`email_verified` DATETIME(3) NULL,
`image` VARCHAR(191) NULL,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updated_at` DATETIME(3) NOT NULL,
`deleted_at` DATETIME(3) NULL,
UNIQUE INDEX `users_email_key`(`email`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
000001_create_users.up.sqlで記述したsqlを実行するには、次のコマンドのようにデータベースのユーザー名やパスワードを入れて実行します。
$ migrate -database="postgres://ユーザー名:パスワード@ホスト名:ポート番号/データベース名?sslmode=disable" -path=database/migrations/ up 1
データベースの情報はdocker-compose.ymlに記述してあります。
...
mysql: # ユーザー名
image: mysql:5.7
container_name: mysql
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: blog # データベース名
MYSQL_USER: docker # ユーザー名
MYSQL_PASSWORD: docker # パスワード
TZ: "Asia/Tokyo"
command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
...
ports:
- 3306:3306 # ポート番号
...
- ユーザー名: docker
- パスワード: docker
- ホスト名: mysql
- ポート番号: 3306
- データベース名: blog
これを先程のコマンドに当てはめた次のコマンドを実行します。
$ migrate -path db/migrations -database "mysql://docker:docker@tcp(mysql:3306)/blog?multiStatements=true" up 1
1/u create_users (272.621597ms)
テーブルを削除
テーブルを削除するときのsqlは000001_create_users.down.sqlで定義します。
-- DeleteTable
DROP TABLE IF EXISTS users;
テーブルを作るときのコマンドとほどんど一緒ですが、up
ではなく down
を使用します。
$ migrate -path db/migrations -database "mysql://root:root@tcp(mysql:3306)/manage" down 1
1/d create_users (106.950515ms)
マイグレーション実行時のエラー
golang-migrateを実行するときのエラーとその解決方法をご紹介します。
error: Dirty database version 1. Fix and force version.
シンタックスエラーなどを含むマイグレーションファイルでテーブルを作ろうとすると、次のようにエラーが出ます。
$ migrate -path db/migrations -database "mysql://docker:docker@tcp(mysql:3306)/blog?multiStatements=true" up 1
error: Dirty database version 1. Fix and force version.
このエラーが出た場合、やることは
- マイグレーションファイルのsqlを修正する
- データベースのschema_migrationsでバージョンが1でdirtyが1になっているレコードを削除
の2つです。
これらが終わってから、再度テーブルを作るコマンドを実行してください。
通常は次のコマンドを実行することでdirtyが0になり、前のバージョンに戻すことができますがバージョン1の場合はレコードを消す必要があります。
migrate -path database/migrations -database "mysql://root:root@tcp(mysql:3306)/manage" force 1
error: file does not exist
マイグレーションファイルがすべて実行済みだと次のエラーが出ます。
$ migrate -path db/migrations -database "mysql://docker:docker@tcp(mysql:3306)/blog?multiStatements=true" up 1
error: file does not exist
マイグレーションの管理はデータベースのschema_migrationsでされているので、実行済みのバージョンのファイルを確認してください。
コメント