tamuraです。 最近、Go言語を始めました。
MySQLにつなぐ
コマンドラインアプリのように1回接続して何か操作して切断、というのであればなんら難しくありません。
package main
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
)
func selectSQL(db *sql.DB) {
rows, err := db.Query("select * from tbl")
if err != nil {
panic(err)
}
defer rows.Close()
for rows.Next() {
var id string
var name string
err := rows.Scan(&id, &name)
if err != nil {
panic(err)
}
fmt.Printf("id:%s\tname:%s\n", id, name)
}
}
func main() {
db, err := sql.Open("mysql", "user:password@tcp(localhost:3306)/database")
if err != nil {
panic(err)
}
defer db.Close()
selectSQL(db)
}
コネクションプール
Webアプリのような長時間動くアプリを作る場合は、コネクションプールを使用するのが一般的です。 Go言語では自前でコネクションプールを持っていて、自動で勝手にうまくやってくれます。
Javaなどをやっていると誤解しやすいのですが、 sql.Open()
で返ってくるのはコネクションではありません。
db.Query
等を実行すると、キャッシュされているコネクションがあればそれを使い、コネクションがなければ新たにコネクションを作ってSQLを実行します。 そのため、sql.Open()
で返ってきた値をどこからでも参照できるようにしておけば問題ありません。
こんなデータベースパッケージを作りました。
package db
import (
"database/sql"
_ "github.com/go-sql-driver/mysql"
)
var db *sql.DB
// データベースに接続する
func DbInit() (*sql.DB, error) {
var err error
db, err = sql.Open("mysql", "user:password@tcp(localhost:3306)/database")
return db, err
}
// データベースから切断する
func DbClose() {
if db != nil {
db.Close()
}
}
// データベースハンドラを取得する
func DbConn() *sql.DB {
return db
}
これをメインで呼び出します。
package main
import (
"./db"
"./web"
)
func main() {
_, err := db.DbInit()
if err != nil {
panic(err)
}
defer db.DbClose()
web.Run()
}
Webアプリではこんな感じで呼び出します。
package web
import (
"fmt"
"log"
"net/http"
"github.com/gorilla/mux"
"../db"
)
func Run() {
router := mux.NewRouter().StrictSlash(true)
router.
Methods("GET").
Path("/api/user").
Handler(http.HandlerFunc(allUser))
log.Fatal(http.ListenAndServe(":8080", router))
}
func allUser(w http.ResponseWriter, r *http.Request) {
db := db.DbConn()
rows, err := db.Query("select * from tbl")
if err != nil {
panic(err)
}
defer rows.Close()
for rows.Next() {
var id string
var name string
err := rows.Scan(&id, &name)
if err != nil {
panic(err)
}
fmt.Fprintf(w, "id:%s\tname:%s\n", id, name)
}
}
プリペアドステートメント
Java等と同様です。
参照系
db.Prepare
して、stmt.Query()
します。
func selectSQL(db *sql.DB, id string) {
stmt, err := db.Prepare("select * from tbl where id = ?")
if err != nil {
panic(err)
}
defer stmt.Close()
rows, err := stmt.Query(id)
if err != nil {
panic(err)
}
defer rows.Close()
for rows.Next() {
var id string
var name string
err := rows.Scan(&id, &name)
if err != nil {
panic(err)
}
fmt.Printf("id:%s\tname:%s\n", id, name)
}
}
更新系
db.Prepare
して、stmt.Exec()
します。 stmt.Exec()
の戻り値からLastInsertId()
やRowsAffected()
を取得することができます。
func updateSQL(db *sql.DB, id string, name string) {
stmt, err := db.Prepare("update tbl set name = ? where id = ?")
if err != nil {
panic(err)
}
defer stmt.Close()
result, err := stmt.Exec(name, id)
if err != nil {
panic(err)
}
c, err := result.RowsAffected()
if err != nil {
panic(err)
}
fmt.Printf("%w行更新しました", c)
}
まとめ
分からなかったらGo言語のソースを見る。 Use the Source, Luke.