環境
- CentOS7
- go1.x
GORM
The fantastic ORM library for Golang, aims to be developer friendly.
Go 言語で MySQL などのデータベースを簡単に扱える ORM マッパー。
MySQL を使ったサンプルを書いてみる。
インストール
※ dep は非推奨
$ cd /path/to/your/project
$ dep ensure -add github.com/jinzhu/gorm
$ dep ensure -add github.com/go-sql-driver/mysql
ファイル構成
- path/to/go/src/psychedelicnekopunch/go-sample/
infrastructure/
├ Config.go
└ DB.go
main.go
データベース準備
- ここでは「test」という DB を作成して使用する
test.users テーブル
CREATE TABLE `users` (
`id` int(10) UNSIGNED NOT NULL,
`name` varchar(100) NOT NULL,
`age` int(10) UNSIGNED NOT NULL,
`is_student` tinyint(1) UNSIGNED NOT NULL,
`created_at` int(10) UNSIGNED NOT NULL
);
接続〜各種サンプル (SQL文直接書く、参照、作成、更新)
infrastructure/Config.go
package infrastructure
type Config struct {
DB struct {
Production struct {
Host string
Username string
Password string
DBName string
}
}
}
func NewConfig() *Config {
c := new(Config)
c.DB.Production.Host = "localhost"
c.DB.Production.Username = "username"
c.DB.Production.Password = "password"
c.DB.Production.DBName = "test"
return c
}
infrastructure/DB.go
- ロールバックが行えるように考慮してみた。
package infrastructure
import (
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
// _ "github.com/go-sql-driver/mysql" ← こっちでも動く
)
type DB struct {
Host string
Username string
Password string
DBName string
Connection *gorm.DB
}
func NewDB() *DB {
c := NewConfig()
return newDB(&DB{
Host: c.DB.Production.Host,
Username: c.DB.Production.Username,
Password: c.DB.Production.Password,
DBName: c.DB.Production.DBName,
})
}
/**
* func Open(dialect string, args ...interface{}) (db *DB, err error)
* https://godoc.org/github.com/jinzhu/gorm#Open
*/
func newDB(d *DB) *DB {
//
// ex) MySQL
// https://github.com/go-sql-driver/mysql#examples
//
// ex) MySQL Parameters
// https://github.com/go-sql-driver/mysql#parameters
db, err := gorm.Open("mysql", d.Username + ":" + d.Password + "@tcp(" + d.Host + ")/" + d.DBName + "?charset=utf8&parseTime=True&loc=Local")
if err != nil {
panic(err.Error())
}
d.Connection = db
return d
}
// Begin begins a transaction
func (db *DB) Begin() *gorm.DB {
return db.Connection.Begin()
}
func (db *DB) Connect() *gorm.DB {
return db.Connection
}
main.go
package main
import (
"fmt"
"time"
"psychedelicnekopunch/go-sample/infrastructure"
)
/*
CREATE TABLE `users` (
`id` int(10) UNSIGNED NOT NULL,
`name` varchar(100) NOT NULL,
`age` int(10) UNSIGNED NOT NULL,
`is_student` tinyint(1) UNSIGNED NOT NULL,
`created_at` int(10) UNSIGNED NOT NULL
);
*/
type Users struct {
ID int `json:"id"`
Name string `json:"name"`
Age int `json:"age"`
IsStudent bool `json:"isStudent"`
CreatedAt int64 `json:"createdAt"`
}
func main() {
d := infrastructure.NewDB()
db := d.Connect()
/**
* 直接SQL文を書く
*/
// テーブル一覧を取得する
// Exec() を使うとエラーになる
// Raw() は Users などのモデルを必要としない書き方ができる
rows, err := db.Raw("show tables").Rows()
if err != nil {
panic(err.Error())
}
defer rows.Close()
for rows.Next() {
var table string
if err := rows.Scan(&table); err != nil {
panic(err.Error())
}
// テーブルを空にする
// 返り値を必要としない SQL 文は Exec() 使った方がわかりやすいかも
db.Exec("TRUNCATE TABLE test." + table)
}
/**
* Create: 作成
*/
user := Users{
Name: "test",
Age: 16,
IsStudent: true,
CreatedAt: time.Now().Unix(),
}
// NewRecord() は AUTO INCREMENT に対応している?ので ID が自動的に付与される
if !db.NewRecord(&user) {
panic("could not create new record")
}
if err := db.Create(&user).Error; err != nil {
panic(err.Error())
}
/**
* Query: 参照系その1
*/
foundUsers := []Users{}
// SELECT * FROM users;
db.Find(&foundUsers)
if len(foundUsers) == 0 {
fmt.Printf("not found users")
}
fmt.Println(foundUsers)
/**
* Save: 更新
*/
foundUser := Users{}
db.First(&foundUser, user.ID)
// 取得できなかったら ID が初期値の 0 になっている。
if foundUser.ID == 0 {
panic("user not found")
}
// age と is_student を更新する
foundUser.Age = 25
foundUser.IsStudent = false
if err := db.Save(&foundUser).Error; err != nil {
panic(err.Error())
}
/**
* Query2: 参照系その2
*/
foundUsers2 := []Users{}
// SELECT * FROM users WHERE age > 20 AND is_student = 0;
db.Where("age > ? and is_student = ?", 20, false).Find(&foundUsers2)
if len(foundUsers2) == 0 {
fmt.Printf("not found users")
}
fmt.Println(foundUsers2)
}
確認
$ go run main.go
[{1 test 16 true 1555567890}]
[{1 test 25 false 1555567890}]