こんにちは suganoo です。
Go言語からのDB操作を復習したいと思います。「Goプログラミング実践入門」でDBの操作が出ていたので、おさらいをしておきたいなと思ってました。
今回はORMは使いません。それはそれでいつかまた調べて記事にしてみようと思います。
DB設定
PostgreSQLのインストール
本記事ではPostgreSQLを使っています。インストール作業は他のサイトなどを見て設定してみてください。
www.dbonline.jp
DB, テーブル設定
プログラムの中でCREATE DATABASE/TABLE からやってみようかなと思いましたが、考えてみてもそんな場面はほとんどないので事前にDB設定とCREATE TABLEはしておきます。
-- データベースは postgresを使います create table members ( id serial primary key, first_name varchar(255), last_name varchar(255), email varchar(255), accessprev boolean ); INSERT INTO members VALUES (1, 'minoru', 'tanaka', 'tanaka@gmail.com', TRUE); INSERT INTO members VALUES (2, 'tadashi', 'sato', 'sato@gmail.com', FALSE); INSERT INTO members VALUES (3, 'sachiko', 'suzuki', 'suzuki@yahoo.co.jp', FALSE);
テーブルの中身を確認するとこうなってると思います。
id | first_name | last_name | accessprev | |
---|---|---|---|---|
1 | minoru | tanaka | tanaka@gmail.com | t |
2 | tadashi | sato | sato@gmail.com | f |
3 | sachiko | suzuki | suzuki@yahoo.co.jp | f |
DB操作
import設定
今回はPostgreSQLを使うので、それ用のdriverをインポートします。
import ( "database/sql" _ "github.com/lib/pq" )
データ取得用 Member構造体
データ取得用にMember構造体を定義しておきます。
type Member struct { Id int FirstName string LastName string Email string AccessPrev bool }
サンプルコード全体
先に以降で説明するサンプルコードを掲載しておきます。
Go言語でDB操作
Query()
単純にクエリ実行したい場合に使えます。
sql - The Go Programming Language
func (db *DB) Query(query string, args ...interface{}) (*Rows, error)
サンプルコード
rows, err := Db.Query("SELECT * FROM members ORDER BY id") if err != nil { return } for rows.Next() { m := Member{} rows.Scan(&m.Id, &m.FirstName, &m.LastName, &m.Email, &m.AccessPrev) fmt.Println(m) }
Query()はRows型を返します。
sql - The Go Programming Language
SQLの結果が複数行を想定しているからです。
そんでそのメソッドのNext()で行があるか判断して、Scan()で値を取得しています。
Query() プレイスホルダー
このQuery()関数はプレイスホルダーも使えます。SQL分に$1, $2, $3 といった書き方をして、引数で実際の値を設定するというものです。
rows, err = Db.Query("SELECT * FROM members WHERE accessprev = $1 ORDER BY id", "false")
値はたいてい別々に取得するものなのでSQL文に入れる必要がないので見やすくなりますね。SQL文の中では$1, $2, $3...の順番はありません、引数に指定する実際の値の順番が$1, $2, $3...になるので順番を間違えないようにしましょう。
QueryRow()
そんで次にQueryRow()です。
https://golang.org/pkg/database/sql/#DB.QueryRow
func (db *DB) QueryRow(query string, args ...interface{}) *Row
QueryRow()はRow型を返します。一行のSQL結果が返るを想定してるのでScan()しかないですね。
サンプルコードです
m := Member{} err = Db.QueryRow("SELECT * FROM members WHERE accessprev = $1 ORDER BY id", "true").Scan(&m.Id, &m.FirstName, &m.LastName, &m.Email, &m.AccessPrev) if err != nil { return } fmt.Println(m)
Prepare()
SQL文だけでStmtオブジェクトを作り、クエリを実行するメソッドと分けることができます。
sql - The Go Programming Language
func (db *DB) Prepare(query string) (*Stmt, error)
サンプルコードです
statement := "SELECT * FROM members WHERE accessprev = $1 ORDER BY id" stmt, err := Db.Prepare(statement) if err != nil { return } defer stmt.Close() rows, err = stmt.Query("false") for rows.Next() { m := Member{} rows.Scan(&m.Id, &m.FirstName, &m.LastName, &m.Email, &m.AccessPrev) fmt.Println(m) }
抜粋ですが実行メソッドが分けられているのがわかるかと思います。
statement := "SELECT * FROM members WHERE accessprev = $1 ORDER BY id" stmt, err := Db.Prepare(statement) defer stmt.Close() // Close()が必要!! rows, err = stmt.Query("false")
Exec()
単純にクエリを実行し、結果行を戻さないメソッドです。たいていは delete, insert で使うと思います。
sql - The Go Programming Language
func (db *DB) Exec(query string, args ...interface{}) (Result, error)
返すResult型を見てもどこの行に入ったかとかを返すようですね。データベース依存みたいです。
sql - The Go Programming Language
サンプルコードです
_, err = Db.Exec("INSERT INTO members VALUES ($1, $2, $3, $4, $5)", 4, "takashi", "yamamoto", "yamamoto@yahoo.co.jp", "FALSE")
Contextも渡せる
ここまで基本的なメソッドを見てきましたが、ドキュメントを見てみるとcontex.Contextを渡せるメソッドも用意されているんですね。
例えば QueryContext()とか
sql - The Go Programming Language
func (db *DB) QueryContext(ctx context.Context, query string, args ...interface{}) (*Rows, error)
確かにSQLでクエリに時間がかかることもありますから、タイムアウト時間も設定したいものです。けっこう便利ですな。
context.Context()の使い方については下記の記事が参考になります。
blog.suganoo.net
Named()はまだSQliteだけみたい
そんでまたドキュメントを見てみるとNamed()メソッドなるものも見つかりました。
sql - The Go Programming Language
func Named(name string, value interface{}) NamedArg
Exampleを見てみると、@で任意のプレイスホルダーを指定できるように見えます。
db.ExecContext(ctx, ` delete from Invoice where TimeCreated < @end and TimeCreated >= @start;`, sql.Named("start", startTime), sql.Named("end", endTime), )
なんだsql.Named() 優秀やーん!!
.....っと思ったのですが、実はこれまだ使えるDBは多くないそうです。
mattn.kaoriya.net
Named()を使えるのはSQLiteだけみたいですね。
私はこれに気づかずPostgreSQLで試行錯誤してみましたが、ぜんぜん使えず半日以上を無駄にしました。
issueにはあるみたいですが、まだ使えないようですね。
github.com
github.com
database/sql ドキュメントのExample
あとdatabase/sqlのドキュメントを調べて気づきましたが、Exampleがことごとくすべてエラーになってます。これいいんですかねえ.....。
golang.org
まあDBがないとできないようなExampleだから、仕方ないといえばそうなのかもだけど。。。
最後
他にもいろいろ関数はありましてColumnType型やカラム一覧が取得できる関数などもありますが、上記の基本的な使い方がわかればあとは何とかなるかと思います。
次回はgormでもやってみたいと思います。
<こんな記事もあります>
blog.suganoo.net
blog.suganoo.net
達人に学ぶDB設計 徹底指南書 初級者で終わりたくないあなたへ
- 作者: ミック
- 出版社/メーカー: 翔泳社
- 発売日: 2012/03/16
- メディア: 単行本(ソフトカバー)
- 購入: 21人 クリック: 316回
- この商品を含むブログ (24件) を見る