LoginSignup
11

More than 3 years have passed since last update.

Gormのオートマイグレーション注意点

Posted at

お題

GolangでORマッパーを探した時に、わりとすぐにヒットするのがGormかなと思う。
スター数も1万超え。
公式ドキュメントも用意され、日本語のドキュメントもある。
ORマッパーとしての機能だけでなく、SQLビルディング、トランザクション制御、リレーション管理、オートマイグレーション、(実行したSQL文を出力する)ロガー等、多くの機能を備えている。
とても便利なのだけど、直感的に使えるがために、ちゃんとドキュメント読まずに使う(いや、読まないのはありえないこととはわかっているのだけど、つい)と当然のようにハマる。

これはドキュメントにはっきり書いてあるので注意点というかドキュメントちゃんと読めば気づくはずなのだけど、『オートマイグレーション』に関しては以下の仕様になっている。
『テーブル、カラムの新規追加は適用されるが、変更や削除は適用されない』
これは(既に登録されている)データの保護のためとのこと。
構造体(例:type User struct{})を定義して db.AutoMigrate(&User{}) とやるとそれだけで接続しているデータベースにテーブルが作成されるのでとても楽ではあるのだけど、何か定義の変更があったら構造体を修正すればそれだけでOKと思うと「おやっ?」となるので注意。

ちなみに、リレーション管理なんかもちょっと「?」と思うところがあるのだけど、それは以前↓で少し書いたので今回は触れず。
[golang]Gormでのモデル定義とオートマイグレーションでできるテーブル定義(リレーション編)

開発環境

# OS

$ cat /etc/os-release 
NAME="Ubuntu"
VERSION="18.04.2 LTS (Bionic Beaver)"

# Golang

$ go version
go version go1.11.4 linux/amd64

実践

お題に書いた通りなので実践も何もないのだけど、一応、動作を確認してみる。
ソースの全量は↓
https://github.com/sky0621/tips-go/tree/master/tools/gorm/part05_migration

DB接続ソース

[main.go]
package main

import (
    "part05_migration/model"

    "github.com/jinzhu/gorm"

    _ "github.com/go-sql-driver/mysql"
)

func main() {
    db, err := gorm.Open("mysql", "testuser:testpass@tcp(127.0.0.1:3306)/testdb?charset=utf8&parseTime=True&loc=Local")
    if err != nil {
        panic(err)
    }
    defer func() {
        if err := db.Close(); err != nil {
            panic(err)
        }
    }()
    db.LogMode(true)
    if err := db.DB().Ping(); err != nil {
        panic(err)
    }

    db.AutoMigrate(
        &model.User{},
    )
}

■1■ ユーザーテーブルを作成

構造体の定義

[model/user.go]
package model

type User struct {
    ID   string `gorm:"primary_key"`
    Name string
}

オートマイグレーション実行(テーブル作成)

$ go run main.go 

(/home/sky0621/work/src/go111/src/github.com/sky0621/tips-go/tools/gorm/part05_migration/main.go:25) 
[2019-04-22 09:05:54]  [55.66ms]  CREATE TABLE `users` (`id` varchar(255),`name` varchar(255) , PRIMARY KEY (`id`))  
[0 rows affected or returned ] 
mysql> desc users;
+-------+--------------+------+-----+---------+-------+
| Field | Type         | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| id    | varchar(255) | NO   | PRI | NULL    |       |
| name  | varchar(255) | YES  |     | NULL    |       |
+-------+--------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

■2■ ユーザーテーブルのカラム追加と組織テーブル追加

構造体の定義

[model/user.go]
package model

type User struct {
    ID       string `gorm:"primary_key"`
    Name     string
    Birthday int
}
[model/organization.go]
package model

type Organization struct {
    ID   string `gorm:"primary_key"`
    Name string
}

オートマイグレーション実行(カラム追加)

$ go run main.go 

(/home/sky0621/work/src/go111/src/github.com/sky0621/tips-go/tools/gorm/part05_migration/main.go:25) 
[2019-04-22 09:12:11]  [96.82ms]  ALTER TABLE `users` ADD `birthday` int;  
[0 rows affected or returned ] 
mysql> desc users;
+----------+--------------+------+-----+---------+-------+
| Field    | Type         | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+-------+
| id       | varchar(255) | NO   | PRI | NULL    |       |
| name     | varchar(255) | YES  |     | NULL    |       |
| birthday | int(11)      | YES  |     | NULL    |       |
+----------+--------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

オートマイグレーション実行(テーブル追加)

オートマイグレーション対象の構造体を追加

$ git diff main.go
diff --git a/tools/gorm/part05_migration/main.go b/tools/gorm/part05_migration/main.go
index 257e20a..311f245 100644
--- a/tools/gorm/part05_migration/main.go
+++ b/tools/gorm/part05_migration/main.go
@@ -24,5 +24,6 @@ func main() {
        }
        db.AutoMigrate(
                &model.User{},
+               &model.Organization{},
        )
 }
$ go run main.go 

(/home/sky0621/work/src/go111/src/github.com/sky0621/tips-go/tools/gorm/part05_migration/main.go:25) 
[2019-04-22 09:16:09]  [53.84ms]  CREATE TABLE `organizations` (`id` varchar(255),`name` varchar(255) , PRIMARY KEY (`id`))  
[0 rows affected or returned ] 
mysql> desc organizations;
+-------+--------------+------+-----+---------+-------+
| Field | Type         | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| id    | varchar(255) | NO   | PRI | NULL    |       |
| name  | varchar(255) | YES  |     | NULL    |       |
+-------+--------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

■3■ ユーザーテーブルのカラム変更・削除と組織テーブル削除

構造体の定義

[model/user.go]
$ git diff model/user.go
diff --git a/tools/gorm/part05_migration/model/user.go b/tools/gorm/part05_migration/model/user.go
index 17e828b..2894a88 100644
--- a/tools/gorm/part05_migration/model/user.go
+++ b/tools/gorm/part05_migration/model/user.go
@@ -1,7 +1,6 @@
 package model

 type User struct {
-       ID       string `gorm:"primary_key"`
-       Name     string
-       Birthday int
+       ID   string `gorm:"primary_key"`
+       Name string `gorm:"column:name;type:varchar(64)"`
 }

オートマイグレーション対象の構造体を削除

[main.go]
$ git diff main.go
diff --git a/tools/gorm/part05_migration/main.go b/tools/gorm/part05_migration/main.go
index 311f245..257e20a 100644
--- a/tools/gorm/part05_migration/main.go
+++ b/tools/gorm/part05_migration/main.go
@@ -24,6 +24,5 @@ func main() {
        }
        db.AutoMigrate(
                &model.User{},
-               &model.Organization{},
        )
 }

オートマイグレーション実行(ユーザーテーブルのカラム変更・削除と組織テーブル削除)

$ go run main.go
$
mysql> desc users;
+----------+--------------+------+-----+---------+-------+
| Field    | Type         | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+-------+
| id       | varchar(255) | NO   | PRI | NULL    |       |
| name     | varchar(255) | YES  |     | NULL    |       |
| birthday | int(11)      | YES  |     | NULL    |       |
+----------+--------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

mysql> desc organizations;
+-------+--------------+------+-----+---------+-------+
| Field | Type         | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| id    | varchar(255) | NO   | PRI | NULL    |       |
| name  | varchar(255) | YES  |     | NULL    |       |
+-------+--------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

ユーザーテーブル、組織テーブルともに定義に変更がない。
(ともにレコードは未投入だったので、レコード有無を問わず、テーブル構造の変更や削除は適用されない様子。)

まとめ

ドキュメント記載通り、テーブル、カラムの新規追加はオートマイグレーション機能の適用対象になるが、変更、削除は適用対象外になっている。

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
11