golang-migrateを使ってmysqlマイグレーションをする

この記事ではgolang-migrateを使ってmysqlのデータベースマイグレーションする方法をご紹介します。

golang-migrateでのマイグレーションはこれらのデータベースに対応しています。

目次

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の設定がわからない・できない方はこちらの書籍が参考になります。

created by Rinker
¥2,693 (2022/09/26 19:09:02時点 Amazon調べ-詳細)

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;

ORMでgormを使う場合はテーブル名を複数名にしてください。

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でされているので、実行済みのバージョンのファイルを確認してください。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

目次