カテゴリー: BackEnd

gorpを使ってDBを操作する

はじめに

今回の記事では、 gorp を使ってDBを操作する方法を紹介します。

GoのORM

GoでDBにアクセスする場合、今回紹介する gorp の他にも様々な選択肢があります。ORMの比較についてはこちらの記事が参考になります。

gorpの紹介

gorp では、シンプルなインタフェースを通してCRUD操作、構造体へのマッピング、トランザクションなどの処理ができます。

insert、update、deleteおよびPK指定のselectの場合、クエリを書くことなく処理できるほか、SQLを書いて実行することもできます。

他にも、テーブルの作成やインデックスを貼ることもできます。

gorpの基本操作

まず初めに、 gorp でのCRUD操作の書き方を見ていきましょう。前提として、以下のような構造体が定義されているものとします。

type User struct {
 Id        int64     `db:"id, primarykey, autoincrement`
 FirstName string    `db:"firstname, notnull, size:16`
 LastName  string    `db:"lastname, notnull, size:16`
 Age       int       `db:"age, notnull`
 gender    int       `db:"gender, notnull"`
 CreatedAt time.Time `db:"created_at, notnull"`
 UpdatedAt time.Time `db:"updated_at, notnull"`
}

`db:xxx` については後ほど説明します。

insert

insertは以下のように記述します。

package main

import (
 "gopkg.in/gorp.v2"
 "time"
)

func main() {
 dbMap := initDb()
 timeNow := time.Now()
 user1 := User{ "Taro", "Yamada", 25, 1, timeNow, timeNow }
 user2 := User{ "Hanako", "Yamada", 20, 2, timeNow, timeNow }
 err := dbMap.Insert(&user1, &user2)
 if err != nil {
  fmt.printf("error! %v", err)
 }
}

func initDb() *gorp.DbMap {
 db, err := sql.Open("mysql", "tcp:localhost:3306*database/user/password")
 if err != nil {
  fmt.printf("error! %v", err)
 }

 dbMap := &gorp.DbMap{Db: db, Dialect: gorp.MySQLDialect{"InnoDB", "UTF8"}}
 return dbMap
}

select

selectは以下のように記述します。

package main

import (
 "gopkg.in/gorp.v2"
 "time"
)

func main() {
 dbMap := initDb()
 var users []User
 _, err := dbMap.Select(&users, "select * from users where gender = ?", 1)
 if err != nil {
  fmt.printf("error! %v", err)
 }
}

func initDb() *gorp.DbMap {
 db, err := sql.Open("mysql", "tcp:localhost:3306*database/user/password")
 if err != nil {
  fmt.printf("error! %v", err)
 }

 dbMap := &gorp.DbMap{Db: db, Dialect: gorp.MySQLDialect{"InnoDB", "UTF8"}}
 return dbMap
}

さらに、以下のようにパラメータを map でbindingすることもできます。

package main

import (
 "gopkg.in/gorp.v2"
 "time"
)

func main() {
 dbMap := initDb()
 user := User{}
 err := dbMap.Select(
  &user, 
  "select * from users where age > :age and gender = :gender", 
  map[string]interface{}{
   "age": 20,
   "gender": 1
  },
 )
 if err != nil {
  fmt.printf("error! %v", err)
 }
}

func initDb() *gorp.DbMap {
 db, err := sql.Open("mysql", "tcp:localhost:3306*database/user/password")
 if err != nil {
  fmt.printf("error! %v", err)
 }

 dbMap := &gorp.DbMap{Db: db, Dialect: gorp.MySQLDialect{"InnoDB", "UTF8"}}
 return dbMap
}

1件だけ取得したい場合は以下のように記述します。ただし、1件も該当しない場合もしくは、複数件該当する場合はエラーが返ります。

package main

import (
 "gopkg.in/gorp.v2"
 "time"
)

func main() {
 dbMap := initDb()
 user := User{}
 err := dbMap.SelectOne(&user, "select * from users where id = ?", 1)
 if err != nil {
  fmt.printf("error! %v", err)
 }
}


func initDb() *gorp.DbMap {
 db, err := sql.Open("mysql", "tcp:localhost:3306*database/user/password")
 if err != nil {
  fmt.printf("error! %v", err)
 }

 dbMap := &gorp.DbMap{Db: db, Dialect: gorp.MySQLDialect{"InnoDB", "UTF8"}}
 return dbMap
}

PKを指定してselectする場合は以下のように記述できます。

package main

import (
 "gopkg.in/gorp.v2"
 "time"
)

func main() {
 dbMap := initDb()
 obj, err := dbMap.Get(User{}, 1)
 if err != nil {
  fmt.printf("error! %v", err)
 }
 user := obj.(*User)
}


func initDb() *gorp.DbMap {
 db, err := sql.Open("mysql", "tcp:localhost:3306*database/user/password")
 if err != nil {
  fmt.printf("error! %v", err)
 }

 dbMap := &gorp.DbMap{Db: db, Dialect: gorp.MySQLDialect{"InnoDB", "UTF8"}}
 return dbMap
}

update

updateは以下のように記述します。count には更新したレコード数が返ります。

package main

import (
 "gopkg.in/gorp.v2"
 "time"
)

func main() {
 dbMap := initDb()
 user := User{}
 err := dbMap.SelectOne(&user, "select * from users where id = ?", 1)
 if err != nil {
  fmt.printf("error! %v", err)
 }

 user.Age = 30
 user.UpdatedAt = time.Now()
 count, err := dbMap.Update(&user)
 if err != nil {
  fmt.printf("error! %v", err)
 }
}

func initDb() *gorp.DbMap {
 db, err := sql.Open("mysql", "tcp:localhost:3306*database/user/password")
 if err != nil {
  fmt.printf("error! %v", err)
 }

 dbMap := &gorp.DbMap{Db: db, Dialect: gorp.MySQLDialect{"InnoDB", "UTF8"}}
 return dbMap
}

delete

deleteは以下のように記述します。ただし、構造体にPKを定義しておく必要があります。

package main

import (
 "gopkg.in/gorp.v2"
 "time"
)

func main() {
 dbMap := initDb()
 user := User{}
 err := dbMap.SelectOne(&user, "select * from users where id = ?", 1)
 if err != nil {
  fmt.printf("error! %v", err)
 }

 count, err := dbMap.Delete(&user)
 if err != nil {
  fmt.printf("error! %v", err)
 }
}

func initDb() *gorp.DbMap {
 db, err := sql.Open("mysql", "tcp:localhost:3306*database/user/password")
 if err != nil {
  fmt.printf("error! %v", err)
 }

 dbMap := &gorp.DbMap{Db: db, Dialect: gorp.MySQLDialect{"InnoDB", "UTF8"}}
 return dbMap
}

構造体のmapping

gorpではSQLの実行結果をmappingする構造体をあらかじめ定義しておく必要があります。先ほど定義した構造体をもとに説明します。

type User struct {
 Id        int64     `db:"id, primarykey, autoincrement`
 FirstName string    `db:"firstname, notnull, size:16`
 LastName  string    `db:"lastname, notnull, size:16`
 Age       int       `db:"age, notnull`
 gender    int       `db:"gender, notnull"`
 CreatedAt time.Time `db:"created_at, notnull"`
 UpdatedAt time.Time `db:"updated_at, notnull"`
}

db: の次の文字列でbindするカラムを指定します。PKの場合は primarykey を記述します。文字列型の場合は size でサイズを指定できます。Nullを許容しない場合は notnull を記述します。

テーブルの作成

gorpではテーブルを作成する関数が用意されています。以下のように記述します。

package main

import (
 "gopkg.in/gorp.v2"
 "time"
)

func main() {
 db, err := sql.Open("mysql", "tcp:localhost:3306*database/user/password")
 dbmap := &gorp.DbMap{Db: db, Dialect: gorp.MySQLDialect{"InnoDB", "UTF8"}}
 t := dbmap.AddTableWithName(Invoice{}, "invoice_test").SetKeys(true, "Id")

 err = dbmap.CreateTablesIfNotExists()
 if err != nil {
  fmt.printf("error! %v", err)
 }
}

さいごに

gorpの基本的な使い方を紹介しました。他にもインデックスの作成やupdateなどのhookなどの機能がありますので、興味がありましたらgo docなどをご覧ください。

おすすめ書籍

   

Hiroki Ono

シェア
執筆者:
Hiroki Ono
タグ: golangGo言語

最近の投稿

フロントエンドで動画デコレーション&レンダリング

はじめに 今回は、以下のように…

3週間 前

Goのクエリビルダー goqu を使ってみる

はじめに 最近携わっているとあ…

1か月 前

【Xcode15】プライバシーマニフェスト対応に備えて

はじめに こんにちは、suzu…

2か月 前

FSMを使った状態管理をGoで実装する

はじめに 一般的なアプリケーシ…

3か月 前