はじめに
以前、Go言語で使えるmigrationライブラリを紹介しました。今回はORMライブラリを紹介します。
ORMライブラリ
Go言語のORMライブラリを2つ紹介します。これらのライブラリを使用することで、DBのデータをstructにマッピングすることができます。それでは、各ライブラリの特徴を簡単に紹介します。
GORM
GORMは「Full-Featured ORM」や「Developer Friendly」を謳う非常に多機能な定番ORMで、これ単体で一通りのことができます。また、ドキュメントも豊富です。
GORMの機能を以下に列挙します。
- Associations (Has One, Has Many, Belongs To, Many To Many, Polymorphism)
- Hooks (Before/After Create/Save/Update/Delete/Find)
- Preloading (eager loading)
- Transactions
- Composite Primary Key
- SQL Builder
- Auto Migrations
- Logger
- Extendable, write Plugins based on GORM callbacks
- Every feature comes with tests
SQLBoiler
SQLBoilerは非常にパフォーマンスの高いORMのようです。migration機能はないので、goose、 sql-migrateや前回紹介したsqldefなどを併用する必要があります。SQLBoilerの使い方についてはこちらが参考になります。
GORMを使ってみる
それでは、実際にGORMを使ってみます。
導入
下記の通りインストールします。
1 | $ go get -u github.com/jinzhu/gorm |
今回はMySQLを使用しますので、こちらもインストールしておきます。
1 | $ go get -u github.com/go-sql-driver/mysql |
migration
nameというフィールドを持つUsersというテーブルを定義します。下記のようにgorm.Modelと記述するとcreated_at、updated_at、deleted_atが定義されます。
1 2 3 4 | type User struct { gorm.Model Name string } |
マイグレーションは下記のように行います。
?parseTime=trueを記述しないと「unsupported Scan, storing driver.Value type []uint8 into type *time.Time」というエラーが発生します。こちらの通りDB側の型とGo言語側の型が違うことで発生するようです。
1 2 3 4 5 6 7 8 9 10 | // user_name:password@host/database_name db, err := gorm.Open("mysql", "root:root@tcp(127.0.0.1:3306)/gorm_test?parseTime=true") if err != nil { panic("failed to connect } defer db.Close() db.AutoMigrate(&User{}) if db.Error != nil { panic(db.Error) } |
実際のテーブルは下記のとおりです。
1 2 3 4 5 6 7 8 9 10 | 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 | | +------------+------------------+------+-----+---------+----------------+ |
insert
insertは下記のように行います。
1 2 3 4 5 | var newUser = &User{Name: "Yamada"} db = db.Create(newUser) if db.Error != nil { panic(db.Error) } |
select
selectは下記のように行います。
1 2 3 4 5 | var user User db.First(&user, "name = ?", "Yamada") if db.Error != nil { panic(db.Error) } |
update
updateは下記のように行います。
1 2 3 4 5 6 7 8 | var user User db.First(&user, "name = ?", "Yamada") if db.Error != nil { panic(db.Error) } user.Name = "Tanaka" db.Save(&user) |
delete
deleteは下記のように行います。
1 2 3 4 5 6 7 8 9 10 | var user User db.First(&user, "name = ?", "Yamada") if db.Error != nil { panic(db.Error) } db.Delete(&user) if db.Error != nil { panic(db.Error) } |
サンプルコード
CRUD操作のサンプルコードは下記のとおりです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | package main import ( "encoding/json" "fmt" "github.com/jinzhu/gorm" _ "github.com/jinzhu/gorm/dialects/mysql" ) type User struct { gorm.Model Name string } func main() { db, err := gorm.Open("mysql", "root:root@tcp(127.0.0.1:3306)/gorm_test?parseTime=true") if err != nil { panic("failed to connect database") } defer db.Close() db.LogMode(true) var newUser = &User{Name: "Yamada"} db.AutoMigrate(&User{}) if db.Error != nil { panic(db.Error) } db = db.Create(newUser) if db.Error != nil { panic(db.Error) } j, _ := json.Marshal(newUser) fmt.Println(string(j)) var user User db.First(&user, "name = ?", "Yamada") if db.Error != nil { panic(db.Error) } j, _ = json.Marshal(user) fmt.Println(string(j)) user.Name = "Tanaka" db.Save(&user) db.First(&user, "name = ?", "Tanaka") if db.Error != nil { panic(db.Error) } j, _ = json.Marshal(user) fmt.Println(string(j)) db.Delete(&user) if db.Error != nil { panic(db.Error) } } |
実行時のログは下記のとおりです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | $ go run main.go (/Users/***/dev/src/test_gorm/main.go:29) [2018-11-18 12:07:38] [1.01ms] INSERT INTO `users` (`created_at`,`updated_at`,`deleted_at`,`name`) VALUES ('2018-11-18 12:07:38','2018-11-18 12:07:38',NULL,'Yamada') [1 rows affected or returned ] {"ID":9,"CreatedAt":"2018-11-18T12:07:38.099754+09:00","UpdatedAt":"2018-11-18T12:07:38.099754+09:00","DeletedAt":null,"Name":"Yamada"} (/Users/***/dev/src/test_gorm/main.go:38) [2018-11-18 12:07:38] [0.58ms] SELECT * FROM `users` WHERE `users`.`deleted_at` IS NULL AND ((name = 'Yamada')) ORDER BY `users`.`id` ASC LIMIT 1 [1 rows affected or returned ] {"ID":9,"CreatedAt":"2018-11-18T03:07:38Z","UpdatedAt":"2018-11-18T103:07:38Z","DeletedAt":null,"Name":"Yamada"} (/Users/***/dev/src/test_gorm/main.go:47) [2018-11-18 12:07:38] [0.40ms] UPDATE `users` SET `created_at` = '2018-11-18 18:07:38', `updated_at` = '2018-11-18 12:07:38', `deleted_at` = NULL, `name` = 'Tanaka' WHERE `users`.`deleted_at` IS NULL AND `users`.`id` = '9' [1 rows affected or returned ] (/Users/***/dev/src/test_gorm/main.go:49) [2018-11-18 12:07:38] [0.40ms] SELECT * FROM `users` WHERE `users`.`deleted_at` IS NULL AND `users`.`id` = '9' AND ((name = 'Tanaka')) ORDER BY `users`.`id` ASC LIMIT 1 [1 rows affected or returned ] {"ID":9,"CreatedAt":"2018-11-18T03:07:38Z","UpdatedAt":"2018-11-18T03:07:38Z","DeletedAt":null,"Name":"Tanaka"} (/Users/***/dev/src/test_gorm/main.go:57) [2018-11-18 12:07:38] [0.40ms] UPDATE `users` SET `deleted_at`='2018-11-18 12:07:38' WHERE `users`.`deleted_at` IS NULL AND `users`.`id` = '9' [1 rows affected or returned ] |
さいごに
今回はGo言語でのORMライブラリを紹介しました。今回はGORMを使ってみましたが、SQLBoilerも実際に動かしてみたいと思います。
なお、Go言語に関してはこちらでも多くの記事を紹介していますので、ぜひご覧ください。