18
21

More than 5 years have passed since last update.

Gormを触ってみた(MySQL)

Posted at

環境

$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.14.4
BuildVersion:   18E226

$ mysql --version
mysql  Ver 8.0.13 for osx10.14 on x86_64 (Homebrew)

準備

項目 内容
DB名 go_sample
ユーザー user1
パスワード Password_01
-- ユーザー追加
mysql> create user 'user1'@'localhost' identified by 'Password_01';
mysql> grant all privileges on `go_sample`.* to user1@localhost;

次のテーブルをGo側で作成する。

mysql> desc go_sample.user;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | NO   | PRI | NULL    |       |
| name  | varchar(52) | YES  |     | NULL    |       |
| age   | int(11)     | YES  |     | NULL    |       |
| sex   | int(11)     | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)

Gormとは

  • Go言語用のORMライブラリで、開発者に優しい

インストール

# gorm
$ go get -u github.com/jinzhu/gorm

# mysqlドライバー入れていない場合
$ go get -u github.com/go-sql-driver/mysql

とりあえず接続してみる

package main

import (
    "fmt"
    "github.com/jinzhu/gorm"
    _ "github.com/jinzhu/gorm/dialects/mysql"
    "log"
)

const (
    // データベース
    Dialect = "mysql"

    // ユーザー名
    DBUser = "user1"

    // パスワード
    DBPass = "Password_01"

    // プロトコル
    DBProtocol = "tcp(127.0.0.1:3306)"

    // DB名
    DBName = "go_sample"
)

func connectGorm() *gorm.DB {
    connectTemplate := "%s:%s@%s/%s"
    connect := fmt.Sprintf(connectTemplate, DBUser, DBPass, DBProtocol, DBName)
    db, err := gorm.Open(Dialect, connect)

    if err != nil {
        log.Println(err.Error())
    }

    return db
}

func main() {
    db := connectGorm()
    defer db.Close()
}

エラーがなければ接続完了。

テーブル定義

次にテーブル構造を定義する。

type User struct {
    gorm.Model
    Name string `gorm:"size:255"`
    Age  int
    Sex  string `gorm:"size:255"`
}

func (u User) String() string {
    return fmt.Sprintf("%s(%d)", u.Name, u.Age)
}

次は自動的にカラムが追加される。
- id
- created_at
- updated_at
- deleted_at

package gorm

import "time"

// Model base model definition, including fields `ID`, `CreatedAt`, `UpdatedAt`, `DeletedAt`, which could be embedded in your models
//    type User struct {
//      gorm.Model
//    }
type Model struct {
    ID        uint `gorm:"primary_key"`
    CreatedAt time.Time
    UpdatedAt time.Time
    DeletedAt *time.Time `sql:"index"`
}

main()関数の末尾に次のコードを追加する。

テーブルが存在しない時に対象のテーブルを作成してくれる。

db.Set("gorm:table_options", "ENGINE = InnoDB").AutoMigrate(&User{})

実行後、usersテーブルが作成されている。

mysql> show tables;
+-------------------------+
| Tables_in_go_sample     |
+-------------------------+
| users                   |
+-------------------------+
1 row in set (0.00 sec)

テーブル構造

mysql> desc users;
+------------+------------------+------+-----+---------+----------------+
| Field      | Type             | Null | Key | Default | Extra          |
+------------+------------------+------+-----+---------+----------------+
| id         | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| created_at | timestamp        | YES  |     | NULL    |                |
| updated_at | timestamp        | YES  |     | NULL    |                |
| deleted_at | timestamp        | YES  | MUL | NULL    |                |
| name       | varchar(255)     | YES  |     | NULL    |                |
| age        | int(11)          | YES  |     | NULL    |                |
| sex        | varchar(255)     | YES  |     | NULL    |                |
+------------+------------------+------+-----+---------+----------------+
7 rows in set (0.00 sec)

データの操作

insert

func insert(users []User, db *gorm.DB) {
    for _, user := range users {
        db.NewRecord(user)
        db.Create(&user)
    }
}

func main() {
  ...
  user1 := User{Name: "山田太郎", Age: 25, Sex: "男"}
    user2 := User{Name: "田中花子", Age: 22, Sex: "女"}
    insertUsers := []User{user1, user2}
    insert(insertUsers, db)
}

実行後のデータは次。

mysql> select * from users;
+----+---------------------+---------------------+------------+--------------+------+------+
| id | created_at          | updated_at          | deleted_at | name         | age  | sex  |
+----+---------------------+---------------------+------------+--------------+------+------+
|  1 | 2019-04-05 04:21:02 | 2019-04-05 04:21:02 | NULL       | 山田太郎     |   25 |    |
|  2 | 2019-04-05 04:21:02 | 2019-04-05 04:21:02 | NULL       | 田中花子     |   22 |    |
+----+---------------------+---------------------+------------+--------------+------+------+
2 rows in set (0.00 sec)

query

全件取得

func findAll(db *gorm.DB) []User {
    var allUsers []User
    db.Find(&allUsers)
    return allUsers
}

func main() {
  ...
  fmt.Println(findAll(db)) // [山田太郎(25) 田中花子(22)]
}

ID昇順で一番初めのユーザー取得

func firstUserByID(db *gorm.DB) User {
    var firstUser User
    db.First(&firstUser)
    return firstUser
}

func main() {
  ...
  fmt.Println(firstUserByID(db)) // 山田太郎(25)
}

IDで検索

func findByID(db *gorm.DB, id int) User {
    var user User
    db.First(&user, id)
    return user
}

func main() {
  fmt.Println(findById(db, 2))   // 田中花子(22)
  // 存在しない場合は初期値が設定される
  fmt.Println(findByID(db, 100)) // (0)
}

名前で検索

func findByName(db *gorm.DB, name string) []User {
    var user []User
    db.Where("name = ?", name).Find(&user)
    return user
}

func main() {
  ...
  fmt.Println(findByName(db, "山田太郎")) // [山田太郎(25)]
}

update

IDをキーに更新

func updateWhereID(id int, db *gorm.DB) {
    db.Model(&user).Where("id = ?", id).Update("age", 30)
}

func main() {
  ...
  updateWhereID(1, db)
    fmt.Println(findAll(db)) // [山田太郎(30) 田中花子(22)]
}

全て更新

func updateAll(db *gorm.DB) {
    db.Model(&user).Update("age", 22)
}

func main() {
  updateAll(db)
  fmt.Println(findAll(db)) // [山田太郎(22) 田中花子(22)]
}

delete

IDをキーに論理削除

func deleteByID(id int, db *gorm.DB) {
    db.Where("id = ?", id).Delete(user)
}

deleteByID(1, db)
fmt.Println(findAll(db)) // []

もしモデルがDeletedAtフィールドを持っていれば自動的に論理削除になり、

テーブル上にはレコードは残っているが、deleted_atに削除された時間が入りこのレコードはGoでは取得されない。

実際に実行されているのはupdate文になる。

  • テーブル
-- before
select * from users;
+----+---------------------+---------------------+------------+--------------+------+------+
| id | created_at          | updated_at          | deleted_at | name         | age  | sex  |
+----+---------------------+---------------------+------------+--------------+------+------+
|  1 | 2019-04-06 04:33:52 | 2019-04-06 04:33:52 | NULL       | 山田太郎     |   25 |    |
|  2 | 2019-04-06 04:33:52 | 2019-04-06 04:33:52 | NULL       | 田中花子     |   22 |    |
+----+---------------------+---------------------+------------+--------------+------+------+
2 rows in set (0.00 sec)

-- after
select * from users;
+----+---------------------+---------------------+---------------------+--------------+------+------+
| id | created_at          | updated_at          | deleted_at          | name         | age  | sex  |
+----+---------------------+---------------------+---------------------+--------------+------+------+
|  1 | 2019-04-06 04:33:52 | 2019-04-06 04:33:52 | 2019-04-06 04:35:29 | 山田太郎     |   25 |    |
|  2 | 2019-04-06 04:33:52 | 2019-04-06 04:33:52 | 2019-04-06 04:35:29 | 田中花子     |   22 |    |
+----+---------------------+---------------------+---------------------+--------------+------+------+
2 rows in set (0.00 sec)

参考

18
21
0

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
18
21