Help us understand the problem. What is going on with this article?

[Go言語] database/sqlパッケージを使ってみた

More than 3 years have passed since last update.

ドライバを入れる

MySQLのドライバをいれてみる。

go get "github.com/go-sql-driver/mysql"

使うときは、init関数を呼び出せばよいみたいなので、_でインポートする。

import _ "github.com/go-sql-driver/mysql"

データベースを開く

ドライバの名前を指定して、データベースに接続する。

cnn := sql.Open("mysql", "user:password@tcp(host:port)/dbname")

1レコードをSELECTしてみる

QueryRowメソッドを使えば、1レコード分を取得できる。
Go言語得意のポイントを渡して、出力引数で受け取る。

id := 100
var name string

if err := cnn.QueryRow("SELECT name FROM person WHERE id = ?LIMIT 1", id).Scan(&name); err != nil {
    log.Fatal(err)
}

fmt.Println(id, name)

複数レコードをSELECTしてみる

Queryメソッドを使えば、複数のレコードを取得できる。

rows, err := cnn.Query("SELECT id, name FROM person")
if err != nil {
    log.Fatal(err)
}
defer rows.Close()

for rows.Next() {
    var id int
    var name string 
    if err := rows.Scan(&id, &name); err != nil {
        log.Fatal(err)
    }
    fmt.Println(id, name)
}

if err := rows.Err(); err != nil {
    log.Fatal(err)
}

UPDATEしてみる

レコードを取得する必要のない、クエリはExecメソッドを使う。

result, err := cnn.Exec("UPDATE person SET name = ? WHERE id = ?", "Hogera", 100)
if err != nil {
    log.Fatal(err)
}

Resultインタフェースを使うと、最後に挿入したレコードのキーや影響の合ったレコード数を取得できる。

type Result interface {
        LastInsertId() (int64, error)
        RowsAffected() (int64, error)
}

トランザクションを使ってみる

トランザクションの開始とコミット

Beginメソッドを呼び出すと、Tx型のポインタとエラー値が返ってくる。
Tx型はDB型と似たようなメソッドを持っているため、QueryQueryRowExecなどが使える。

tx, err := cnn.Begin()
if err != nil {
    log.Fatal(err)
}

Commitメソッドを使えばコミットできる。

tx.Commit()

ロールバック

Rollbackメソッドでロールバックできる。
以下の例は、パニックが起きたら、ロールバックする例である。

func hoge(tx *sql.Tx) {
    defer func() {
        // panicがおきたらロールバック
        if err := recover(); err != nil {
            tx.Rollback()
        }
    }()
    // …
    tx.Exec(…)
}

感想

ドキュメントを見ると、コネクションプールとかよしなにやってくれるらしい。
最初は以下のようにやってたけど、不要のようだ。

var cnnPool chan *sql.DB

func main() {
    cnnPool = make(chan *sql.DB, 10)
    for i := 0; i < cap(cnnPool); i++ {
        cnnPool <- sql.Open("mysql", "user:password@tpc(host:port)/dbname")
    }
}

func getFromDB() { 
    cnn := <-cnnPool
    defer func() {
        cnnPool <- cnn
    }()
    // cnnを使った処理
}

まだまだ、使い始めたばっかなので、基本的な使い方だけまとめた。

tenntenn
Go engineer / Gopher artist
mercari
フリマアプリ「メルカリ」を、グローバルで開発しています。
https://tech.mercari.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away