環境
$ 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)