Go で MySQL につなぐ

MySQL

せっかくなので 8系つかってみる

$ docker pull mysql:8.0.12

$ docker run -v /tmp/:/etc/mysql/conf.d --name mysql8 -e MYSQL_ROOT_PASSWORD=wa9wa9 -d -p 13306:3306 --rm mysql:8.0.12
    
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS              PORTS                     NAMES
972d2a9f1070        mysql:8.0.12        "docker-entrypoint.s…"   About a minute ago   Up About a minute   0.0.0.0:13306->3306/tcp   mysql8

データベース準備

[(none)] mysql> create database sample;
Query OK, 1 row affected (0.05 sec)

[(none)] mysql> create table sample.users(id int auto_increment, name varchar(20), index(id));
Query OK, 0 rows affected (0.07 sec)

[(none)] mysql> insert into sample.users (name) values ("7kaji");
Query OK, 1 row affected (0.09 sec)

[(none)] mysql> insert into sample.users (name) values ("8kaji");
Query OK, 1 row affected (0.05 sec)

[(none)] mysql> select * from sample.users;
+----+-------+
| id | name  |
+----+-------+
|  1 | 7kaji |
|  2 | 8kaji |
+----+-------+
2 rows in set (0.00 sec)

Go

go で使うには、MySQL のドライバを入れる必要がある

$ go get -u github.com/go-sql-driver/mysql

main.go

package main

import (
    "database/sql"
    "fmt"
    "io"
    "net/http"

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

var db *sql.DB
var err error

func main() {
    db = DBConnect()
    defer db.Close()

    // routing 
    http.HandleFunc("/", index)
    http.HandleFunc("/users", users)

    http.Handle("/favicon.ico", http.NotFoundHandler())
    err := http.ListenAndServe(":8080", nil)
    check(err)
}

func index(w http.ResponseWriter, req *http.Request) {
    _, err := io.WriteString(w, "at index")
    check(err)
}

func users(w http.ResponseWriter, req *http.Request) {
    rows, err := db.Query(`SELECT name FROM users;`)
    check(err)
    defer rows.Close()

    var name string
    for rows.Next() {
        err = rows.Scan(&name)
        check(err)
        fmt.Fprintln(w, "name: ", name)
    }
}

// DBConnect returnes *sql.DB
func DBConnect() (db *sql.DB) {
    // TODO: 環境変数からもってくる
    dbDriver := "mysql"
    dbHost := "127.0.0.1"
    dbPort := "13306"
    dbUser := "root"
    dbPass := "wa9wa9"
    dbName := "sample"
    dbOptions := "?parseTime=true"
    db, err = sql.Open(dbDriver, dbUser+":"+dbPass+"@"+"tcp("+dbHost+":"+dbPort+")/"+dbName+dbOptions)
    check(err)
    // defer db.Close()

    err = db.Ping()
    check(err)
    return db
}

func check(err error) {
    if err != nil {
        fmt.Println(err)
    }
}

起動

$ go run main.go

ユーザ一覧

みてみる

$ curl localhost:8080/users
name: 7kaji
name: 8kaji

defer

  • Go  の後処理
  • Ruby でいう begin / rescure /ensure
  • 後処理が必要なオブジェクトを作ったときは、エラーチェックをして直後に defer で後処理する
  • 今回の例では、DB接続に失敗した場合にpanic()が発生して、その後必ず db.Close()が実行される

package main

import (
    "fmt"
)

func main() {
    fmt.Print("1")
    defer fmt.Print("2")
 
    fmt.Print("3")
    defer fmt.Print("4")

    fmt.Print("5")
    defer fmt.Print("6")    
}

=> 135642

TODO

  • 更新系, トランザクション試してみる
  • ORM 使ってみる (Gorm ってのがイチバンメジャーなやつっぽい)
  • JSON でレスポンス返す 
  • ログ出す

REF

qiita.com