LoginSignup
73
38

More than 5 years have passed since last update.

GoでMySQLにアクセスしてみる(gorp編)

Last updated at Posted at 2017-12-02

まずはGoの標準パッケージでアクセスしてみる

GoにはRDBにアクセスするためのdatabase/sqlが標準で用意されています
普通に使用するのには特に問題はありません

Query

// 接続 
db, err := sql.Open("mysql", "user:password@tcp(xx.xx.xx.xx:3306)/db?parseTime=true")
defer db.Close()

// Select
rows, err := db.Query("select * from user")
defer rows.Close()

// 構造体へマッピング
for rows.Next() {
    user := User{}
    err := rows.Scan(&user.Id, &user.Name)
}

Insert

_, err = db.Exec("insert into user values (?, ?, ?) ", 1, "hoge", 30)

SelectのSQLを発行する部分はシンプルで良いが、構造体に値をマッピングする処理が煩雑
Insertでは構造体を直接追加したいのにSQLで書くのは煩雑
もっとスッキリ書きたい

そこでORM(gorp)を使ってアクセスしてみる

gorp(Go Relational Persistence)
https://github.com/go-gorp/gorp

gorpについて(特徴など)
- GolangのORMの一つ
- SelectはSQLを直書き。複雑なQueryとかも自由に直接かけるのでORMでよくあるパフォーマンスがでないとか気にしなくて良い
- 取得結果と構造体とのマッピングはORMがやってくれる
- Insert,Update,DeleteはSQL書かなくても良い

Select

// 接続 
db, err := sql.Open("mysql", "user:password@tcp(xx.xx.xx.xx:3306)/db?parseTime=true")
dbmap := &gorp.DbMap{Db: db, Dialect: gorp.MySQLDialect{"InnoDB", "UTF8"}}
defer dbmap.Db.Close()

// Select複数行
var users []User
_, err := dbmap.Select(&users, "select * from user order by id")

// Select単一行
var user1 User
err = dbmap.SelectOne(&user1, "select * from user where id=?", 1)

// PKで取得
obj, err := dbmap.Get(User{}, 1)
user2 := obj.(*User)


接続文字列に?parseTime=trueを書くと日時をGolangのtimeにParseしてくれる
構造体へのマッピングはgorpが行ってくれるのでポインタを渡すのみ
簡単ですね

構造体とのマッピング定義

type User struct {
    Id        int64      `db:"id, primarykey"`
    Name      string     `db:"name"`
    Age       int64      `db:"age"`
}

タグでマッピングするカラム名を指定できるので、構造体のプロパティ名と異なっていても大丈夫
テーブル名が構造体の名前と異なっている場合は下記コードでマッピングが必要
Insert/Updateを利用する場合はprimarykeyでPKを指定します
autoincrementとかも指定可能

dbmap := dbmap.AddTableWithName(User{}, "user").SetKeys(false, "Id")

コードでテーブルのマッピングを指定する。コードでprimarykeyの指定も可能
テーブル名を構造体に合わせれば問題ないのですが、異なっている場合はdbmapを生成する毎に書かなければいけないので、なんとかならないかな。。

Insert/Update/Delete

user1 := &User{1, "ほげ 太郎", 23}
user2 := &User{2, "ふが 二郎", 41}

// Insert
err := dbmap.Insert(user1, user2)

// Update
user1.Age=42
count, err := dbmap.Update(user1)

// Delete
count, err := dbmap.Delete(user1)

Transaction

トランザクションも使えます

// Begin
tx, err := dbmap.Begin()

//(省略)...
tx.Insert(user1)
tx.Insert(user2)

// Commit
tx.Commit()

その他の機能

  • Create/Drop Tables
    • 構造体からDBをマイグレーションする機能、構造体のタグで桁数とかも指定できるし、Indexも定義できる
  • Hooks
    • Insert,Update直前に処理を追加。作成日時、更新日時を設定したりするのに使える
  • Optimistic Locking
    • versionカラムを追加することで楽観的排他をORMが行ってくれる。RailsのActiveRecordみたいですね

ハマりポイント

  • import _ "github.com/go-sql-driver/mysql"でドライバーを初期化は忘れずに
  • 構造体のプロパティのマッピングはタグでできるがテーブルとのマッピングはコードでしかできないので、毎回書くしかない
  • 日付を扱う場合は接続文字列にparseTime=trueを書きましょう

所感

  • gorpは構造体にマッピングしてくれるため、すっきりコードが書ける
  • SQLを直接書けるので学習コストの低く、ORMにありがちがパフォーマンス問題(ORMが発行するSQLが遅い)も回避できる
  • やろうと思えがDBマイグレーションや楽観的排他等RailsのActiveRecordのような機能も使える
  • gorpは機能と使い勝手がほどよいORMだと思いました(ActiveRecordのような多機能なORMもありますが、私にはこれくらいがほどよい)

※コードが見やすいようにエラー処理は省略してます

73
38
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
73
38