LoginSignup
44

More than 5 years have passed since last update.

Revelでgorpを使ってDBを操作する

Last updated at Posted at 2014-04-25

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が使えました。

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
44