gorp
gorpはgolangのORMライブラリの中で一番人気がありそうな「ORM-ish Library」。
本稿ではgolangのフルスタックWAFのRevel(現在ネイティブでサポートされているORMがない)でgorpを使ってみます。
gorp controllerの作成
ORMがネイティブでサポートされていないので、DB初期化処理やtransaction処理を自分で書く必要があります。
app/controllers/init.go
ここにcontrollersのinit関数を書き、gorp controllerのメソッドをOnAppStartやInterceptMethodに登録します。
package controllers
import "github.com/revel/revel"
func init() {
revel.OnAppStart(InitDB) // DBやテーブルの作成
revel.InterceptMethod((*GorpController).Begin, revel.BEFORE) // transaction開始
revel.InterceptMethod((*GorpController).Commit, revel.AFTER) // 変更反映
revel.InterceptMethod((*GorpController).Rollback, revel.FINALLY) // 異常時処理
}
app/models/user.go
テーブル作りたいので先にモデル定義しときます
package models
type User struct {
Id int
Name string
}
app/controllers/gorp.go
DB初期化
Userモデルのためのテーブルを作成します
mattnさんの記事が参考になります
package controllers
import (
"database/sql"
"github.com/coopernurse/gorp"
_ "github.com/mattn/go-sqlite3"
"github.com/revel/revel" // あとで使います
"APP_NAME/app/models" // revel new APP_NAME の APP_NAME
)
var (
DbMap *gorp.DbMap // このデータベースマッパーからSQLを流す
)
func InitDB() {
db, err := sql.Open("sqlite3", "./app.db")
if err != nil {
panic(err.Error())
}
DbMap = &gorp.DbMap{Db: db, Dialect: gorp.SqliteDialect{}}
// ここで好きにテーブルを定義する
t := DbMap.AddTable(models.User{}).SetKeys(true, "Id")
t.ColMap("Name").MaxSize = 20
DbMap.CreateTables()
}
Begin
ここからtransaction処理のためのGorpControllerを定義します
まずrevel.BEFORE
でtransactionを開始する必要があります
type GorpController struct {
*revel.Controller
Transaction *gorp.Transaction
}
func (c *GorpController) Begin() revel.Result {
txn, err := DbMap.Begin() // ここで開始したtransactionをCOMMITする
if err != nil {
panic(err)
}
c.Transaction = txn
return nil
}
Commit
revel.AFTER
でDbMapに登録しておいたSQLをCOMMITします
func (c *GorpController) Commit() revel.Result {
if c.Transaction == nil {
return nil
}
err := c.Transaction.Commit() // SQLによる変更をDBに反映
if err != nil && err != sql.ErrTxDone {
panic(err)
}
c.Transaction = nil // 正常終了した場合はROLLBACK処理に入らないようにする
return nil
}
ほぼ例外処理ですね
Rollback
Commitで問題があった場合revel.FINALLY
でROLLBACKします
func (c *GorpController) Rollback() revel.Result {
if c.Transaction == nil {
return nil
}
err := c.Transaction.Rollback() // 問題があった場合変更前の状態に戻す
if err != nil && err != sql.ErrTxDone {
panic(err)
}
c.Transaction = nil
return nil
}
下準備は完了です。お疲れ様でした。
SQLを発行してみる
クエリの発行方法はgorpのAPI docをご覧ください
package controllers
import (
"fmt"
"github.com/revel/revel"
"APP_NAME/app/models"
)
type App struct {
*revel.Controller
}
func (c App) Index() revel.Result {
for i := 0; i < 10; i++ {
DbMap.Insert(&models.User{0, fmt.Sprintf("user%d", i)})
}
rows, _ := DbMap.Select(models.User{}, "select * from user")
for _, row := range rows {
user := row.(*models.User)
fmt.Printf("%d, %s\n", user.Id, user.Name)
}
return c.Render()
}
結果は以下のようになります
1, user0
2, user1
3, user2
4, user3
5, user4
6, user5
7, user6
8, user7
9, user8
10, user9
無事DBが使えました。