鱒身(Masu_mi)のブログ

知った事をメモする場所。

gorp を使ってみた

GoでSQLを扱うのに gorp を試してみた。 Go でのDB(RDBMS)との話し方はgorp 含めQiita記事 にアプローチ毎に整理されて紹介されている。

coopernurse/gorp Package gorp provides a simple way to marshal Go structs to and from SQL databases.

特に公式mattnさんの記事 が参考になる。

使い方

大雑把に下の流れが必要。各種クエリにはトランザクションもサポートされている。

  1. *DbMap を取得する(DBを扱う準備をする)
  2. *TableMap を登録する(構造体をテーブルに紐付ける)
  3. 各種クエリを利用する

Webアプリなどでアクセスの度にDBをオープンしたり構造体とテーブルの紐付けしたりするのも馬鹿らしいので、 model用のパッケージなどで永続的に保持しておくのが良い。

簡単な利用例

基本的な使い方を下記のサンプルを追いながら説明する。

package main

import (
  "database/sql"
  "fmt"
  "os"

  "encoding/json"

  _ "github.com/mattn/go-sqlite3"
  "gopkg.in/gorp.v1"
)

func main() {
  // DBを扱う準備をする
  var (
    db, _ = sql.Open("sqlite3", "./test.db")
    dbmap = &gorp.DbMap{Db: db, Dialect: gorp.SqliteDialect{}}
  )

  // 構造体をテーブルに紐付ける
  type Action struct {
    ID        int `db:"id"`
    Name      string
    DebugInfo string `db:"-"`
  }

  // // idをPRIMARYに設定しインクリメンタルにしている
  var t = dbmap.AddTableWithName(Action{}, "action").SetKeys(true, "id")
  t.ColMap("Name").Rename("name")
  // 各種クエリを利用する
  // // テーブルをDROP & CREATE する
  dbmap.DropTables()
  _ = dbmap.CreateTables()
  // // データを追加する
  dbmap.Insert(&Action{ID: 12, Name: "HASHIRU!!", DebugInfo: "no column"})
  // // データを取得する
  list, _ := dbmap.Select(&Action{}, "SELECT * FROM action")
  var result []Action
  for _, p := range list {
    result = append(result, *p.(*Action))
  }
  res, _ := json.Marshal(result)
  fmt.Fprint(os.Stdout, string(res))
}
//*

簡単な解説: DBを扱う準備をする

まずDBを使うために sql.Open の第一引数に “sqlite3” といったDBの名前を渡している。 これによって database/sql 内の drivers マップからDBドライバを選択している。

この drivers マップは事前にドライバが登録されている必要がある。 この登録作業は各パッケージの init 関数で行われる事が多い様だ。 go-sqlite3init関数の中で”sqlite3” を登録している

例えば上記ではコード内でgo-sqlite3 の識別子を使わない。 でもinit を実行しdatabase/sql から使える様にしたい。 そのため先頭でブランクインポート している。

またdatabase/sql から扱えるドライバ一覧 もあるので何が使えるか参考にするといい。

簡単な解説: 構造体をテーブルに紐付ける

DBにはテーブルがあるものだけど gorpAddTable などを使い構造体をテーブルに紐付ける必要がある。 AddTable によって返される*TableMap を用いてテーブルの設定をする。

また登録する構造体にタグを付ける事でフィールドと対応する名前を指定できる。 上記のコードではdb:”id” と名前を指定している。 db:”-“ と名前をハイフンにした場合、Transientが有効になり DBに登録されない っぽい。 SetKeys はプライマリキーを決めるのに使われる。 ユニークキーを決めたり自動でバージョニングするために機能などもあるのでColumnMap について調べると良い。

既にDB内にテーブルが存在する場合でも上記の紐付けは行う必要がある。 紐付け情報は利用後に保持する必要があるため global 変数で保持するなりが必要となる。

簡単な解説: 各種クエリを利用する

SQLを実行してみる。*DbMap のメソッドとして色々定義されている。 ここではExec, Get, Select の差を紹介する。

Exec, Get, Select の違い

ドキュメントに明記されているけど以下の様になる

Exec 任意のSQLを実行できる database/sqlExec と一致
Get プライマリキーを利用して1行取得する
Select Select 文を渡す事でSELECT 文を実行する目的データのスライスを受け取る

ちなみにトランザクション・トレースはサポートされている。 (*DbMap)Begin で開始できる。 トランザクションに対する操作は*Transaction を読むと色々出てるので追うと良い。

トレース機能も紹介だけしておく。 TraceOn(prefix string, logger GorpLogger) でトレースを開始して TraceOff() でトレースを終了する。 渡すGorpLoggerPrintf メソッドを要求するインタフェースでWriter ではないので注意する。