PostgreSQLにアクセスする

標準ライブラリであるdatabase/sqlを利用してPostgreSQLにアクセスしてみます。

チュートリアルがあるので詳細はこちらを見ると良いです。

Go database/sql tutorial

データベースドライバのインストー

SQLDrivers にドライバの一覧があります。
PostgreSQLのドライバがいくつかありますが今回はlib/pqを利用します。

$ go get github.com/lib/pq

データベースへの接続

sql.Open()でデータベースオブジェクトを生成します。この関数は*sql.DBを返します。

db, err := sql.Open("postgres", "host=localhost port=32768 user=postgres dbname=golang_dev sslmode=disable")

sql.Open()はドライバや接続文字列のバリデーションをしているだけで実際は接続しません。
db.Ping()したりクエリを発行した時点でコネクションが確立します。

クエリの発行

参照系は複数件取得するdb.Query()、1件取得するdb.QueryRow()を利用します。

rows, err := db.Query("select id, name from users where id = $1", 1)

for rows.Next() {
    err := rows.Scan(&id, &name)
}

rows.Scan()は渡した変数の型に応じてタイプキャストしてくれます。
例えばidはデータベース上bigintで定義していますが変数id stringを渡せば文字列型で取得できます。(あまりよろしくないと思いますが)

キャストできない型は当然エラーになります。

sql: Scan error on column index 1: converting driver.Value type string ("foo") to a int: invalid syntax

更新系はdb.Exec()を利用します。

db.Exec("insert into users (name) values ($1)", "foo")

プリペアドステートメントを使えるdb.Prepare()とかもあります。

関数化とかしてませんがまとめるとこんな感じ。

package main

import (
    "database/sql"
    _ "github.com/lib/pq"
    "log"
)

func main() {
    // DBオブジェクト生成
    db, err := sql.Open("postgres", "host=localhost port=32768 user=postgres dbname=golang_dev sslmode=disable")

    if err != nil {
        log.Fatal(err)
    }

    defer db.Close()

    // 疎通確認
    err = db.Ping()

    if err != nil {
        log.Fatal(err)
    }

    // 登録
    stmt, err := db.Prepare("insert into users (name) values ($1)")

    if err != nil {
        log.Fatal(err)
    }

    res, err := stmt.Exec("Foo")

    if err != nil {
        log.Fatal(err)
    }

    rowCnt, err := res.RowsAffected()

    if err != nil {
        log.Fatal(err)
    }

    log.Printf("affected = %d\n", rowCnt)

    // 取得
    var (
        id   int
        name string
    )

    rows, err := db.Query("select id, name from users")

    if err != nil {
        log.Fatal(err)
    }

    defer rows.Close()

    for rows.Next() {
        err := rows.Scan(&id, &name)

        if err != nil {
            log.Fatal(err)
        }

        log.Println(id, name)
    }

    err = rows.Err()

    if err != nil {
        log.Fatal(err)
    }
}