はじめに
今回の記事では、 gorp を使ってDBを操作する方法を紹介します。
GoのORM
GoでDBにアクセスする場合、今回紹介する gorp の他にも様々な選択肢があります。ORMの比較についてはこちらの記事が参考になります。
gorpの紹介
gorp では、シンプルなインタフェースを通してCRUD操作、構造体へのマッピング、トランザクションなどの処理ができます。
insert、update、deleteおよびPK指定のselectの場合、クエリを書くことなく処理できるほか、SQLを書いて実行することもできます。
他にも、テーブルの作成やインデックスを貼ることもできます。
gorpの基本操作
まず初めに、 gorp でのCRUD操作の書き方を見ていきましょう。前提として、以下のような構造体が定義されているものとします。
1 2 3 4 5 6 7 8 9 | typeUserstruct{ 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は以下のように記述します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | packagemain import( "gopkg.in/gorp.v2" "time" ) funcmain(){ 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) iferr!=nil{ fmt.printf("error! %v",err) } } funcinitDb()*gorp.DbMap{ db,err:=sql.Open("mysql","tcp:localhost:3306*database/user/password") iferr!=nil{ fmt.printf("error! %v",err) } dbMap:=&gorp.DbMap{Db:db,Dialect:gorp.MySQLDialect{"InnoDB","UTF8"}} returndbMap } |
select
selectは以下のように記述します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | packagemain import( "gopkg.in/gorp.v2" "time" ) funcmain(){ dbMap:=initDb() varusers[]User _,err:=dbMap.Select(&users,"select * from users where gender = ?",1) iferr!=nil{ fmt.printf("error! %v",err) } } funcinitDb()*gorp.DbMap{ db,err:=sql.Open("mysql","tcp:localhost:3306*database/user/password") iferr!=nil{ fmt.printf("error! %v",err) } dbMap:=&gorp.DbMap{Db:db,Dialect:gorp.MySQLDialect{"InnoDB","UTF8"}} returndbMap } |
さらに、以下のようにパラメータを map でbindingすることもできます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | packagemain import( "gopkg.in/gorp.v2" "time" ) funcmain(){ dbMap:=initDb() user:=User{} err:=dbMap.Select( &user, "select * from users where age > :age and gender = :gender", map[string]interface{}{ "age":20, "gender":1 }, ) iferr!=nil{ fmt.printf("error! %v",err) } } funcinitDb()*gorp.DbMap{ db,err:=sql.Open("mysql","tcp:localhost:3306*database/user/password") iferr!=nil{ fmt.printf("error! %v",err) } dbMap:=&gorp.DbMap{Db:db,Dialect:gorp.MySQLDialect{"InnoDB","UTF8"}} returndbMap } |
1件だけ取得したい場合は以下のように記述します。ただし、1件も該当しない場合もしくは、複数件該当する場合はエラーが返ります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | packagemain import( "gopkg.in/gorp.v2" "time" ) funcmain(){ dbMap:=initDb() user:=User{} err:=dbMap.SelectOne(&user,"select * from users where id = ?",1) iferr!=nil{ fmt.printf("error! %v",err) } } funcinitDb()*gorp.DbMap{ db,err:=sql.Open("mysql","tcp:localhost:3306*database/user/password") iferr!=nil{ fmt.printf("error! %v",err) } dbMap:=&gorp.DbMap{Db:db,Dialect:gorp.MySQLDialect{"InnoDB","UTF8"}} returndbMap } |
PKを指定してselectする場合は以下のように記述できます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | packagemain import( "gopkg.in/gorp.v2" "time" ) funcmain(){ dbMap:=initDb() obj,err:=dbMap.Get(User{},1) iferr!=nil{ fmt.printf("error! %v",err) } user:=obj.(*User) } funcinitDb()*gorp.DbMap{ db,err:=sql.Open("mysql","tcp:localhost:3306*database/user/password") iferr!=nil{ fmt.printf("error! %v",err) } dbMap:=&gorp.DbMap{Db:db,Dialect:gorp.MySQLDialect{"InnoDB","UTF8"}} returndbMap } |
update
updateは以下のように記述します。count には更新したレコード数が返ります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | packagemain import( "gopkg.in/gorp.v2" "time" ) funcmain(){ dbMap:=initDb() user:=User{} err:=dbMap.SelectOne(&user,"select * from users where id = ?",1) iferr!=nil{ fmt.printf("error! %v",err) } user.Age=30 user.UpdatedAt=time.Now() count,err:=dbMap.Update(&user) iferr!=nil{ fmt.printf("error! %v",err) } } funcinitDb()*gorp.DbMap{ db,err:=sql.Open("mysql","tcp:localhost:3306*database/user/password") iferr!=nil{ fmt.printf("error! %v",err) } dbMap:=&gorp.DbMap{Db:db,Dialect:gorp.MySQLDialect{"InnoDB","UTF8"}} returndbMap } |
delete
deleteは以下のように記述します。ただし、構造体にPKを定義しておく必要があります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | packagemain import( "gopkg.in/gorp.v2" "time" ) funcmain(){ dbMap:=initDb() user:=User{} err:=dbMap.SelectOne(&user,"select * from users where id = ?",1) iferr!=nil{ fmt.printf("error! %v",err) } count,err:=dbMap.Delete(&user) iferr!=nil{ fmt.printf("error! %v",err) } } funcinitDb()*gorp.DbMap{ db,err:=sql.Open("mysql","tcp:localhost:3306*database/user/password") iferr!=nil{ fmt.printf("error! %v",err) } dbMap:=&gorp.DbMap{Db:db,Dialect:gorp.MySQLDialect{"InnoDB","UTF8"}} returndbMap } |
構造体のmapping
gorpではSQLの実行結果をmappingする構造体をあらかじめ定義しておく必要があります。先ほど定義した構造体をもとに説明します。
1 2 3 4 5 6 7 8 9 | typeUserstruct{ 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ではテーブルを作成する関数が用意されています。以下のように記述します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | packagemain import( "gopkg.in/gorp.v2" "time" ) funcmain(){ 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() iferr!=nil{ fmt.printf("error! %v",err) } } |
さいごに
gorpの基本的な使い方を紹介しました。他にもインデックスの作成やupdateなどのhookなどの機能がありますので、興味がありましたらgo docなどをご覧ください。