Skip to content

Instantly share code, notes, and snippets.

@yosuke-furukawa
Created January 22, 2014 03:07
Show Gist options
  • Save yosuke-furukawa/8552841 to your computer and use it in GitHub Desktop.
Save yosuke-furukawa/8552841 to your computer and use it in GitHub Desktop.

GolangでWebAppを作るとき(その2)

今回はDB接続周りの話

database接続に関してはGolangは標準パッケージにDB接続用のモジュールが存在する。

http://golang.org/pkg/database/sql/

チュートリアル: http://go-database-sql.org/

日本語資料: https://github.com/astaxie/build-web-application-with-golang/tree/master/ja

で、この辺りで調査したことを報告。

database/sqlとmysqlドライバーを使って接続してみる

package main

import (
	"database/sql"
	_ "github.com/go-sql-driver/mysql"
	"log"
)

func main() {
	db, err := sql.Open("mysql",
		"root@tcp(127.0.0.1:3306)/hello")
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()
}

超簡単な接続するだけexample

頑張って解説

package main

import (
	"database/sql"
	_ "github.com/go-sql-driver/mysql"
	"log"
)

func main() {
    // sql.Open 第一引数にdriverの種類、第二引数に接続アドレスを指定、ここではhelloに接続することを宣言。
	db, err := sql.Open("mysql",
		"root@tcp(127.0.0.1:3306)/hello")
	// errがあればそれを表示
	if err != nil {
		log.Fatal(err)
	}
	// deferで関数の終わりにそれをclose
	defer db.Close()
}

dbに対して生存チェックをすることも可能。生存チェックはdb.Pingを使う。

func main() {
	db, err := sql.Open("mysql",
		"root@tcp(127.0.0.1:3306)/hello")
	if err != nil {
		log.Fatal(err)
	}
	err = db.Ping()
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()
}

SELECTしてみる

じゃあ次にエントリを取り出してみましょう。

mysqlに対して、事前にデータを作っておいてください。

create database hello

use hello

create table users
(
 id INT(10) NOT NULL,
 name VARCHAR(32)
);

insert into users (id, name) values (1, "yosuke");
package main

import (
	"database/sql"
	_ "github.com/go-sql-driver/mysql"
	"log"
)

func main() {
	db, err := sql.Open("mysql",
		"root@tcp(127.0.0.1:3306)/hello")
	if err != nil {
		log.Fatal(err)
	}
	err = db.Ping()
	if err != nil {
		log.Fatal(err)
	}

        // idとnameの変数を宣言
	var (
		id   int
		name string
	)

        // db.Queryを使う。
	rows, err := db.Query("select id, name from users where id = ?", 1)
	if err != nil {
		log.Fatal(err)
	}
	defer rows.Close()
	// rowsのNextでカーソルを操作
	for rows.Next() {
	        // rows.Scanで値をバインドする
		err := rows.Scan(&id, &name)
		if err != nil {
			log.Fatal(err)
		}
		// 出力!!
		log.Println(id, name)
	}
	err = rows.Err()
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()
}

ちなみにPrepared Statementを使うとき

	// db.Prepareで実行
	stmt, err := db.Prepare("select id, name from users where id = ?")
	if err != nil {
		log.Fatal(err)
	}
	// statementのClose忘れずに。
	defer stmt.Close()
	// stmt.QueryでQueryを実行
	rows, err := stmt.Query(1);
	for rows.Next() {
		err := rows.Scan(&id, &name)
		if err != nil {
			log.Fatal(err)
		}
		log.Println(id, name)
	}
	defer rows.Close();

でもID一致ならわざわざ毎回Nextとかしたくない、一件しかないし。

こういう時はQueryRowを使いましょう。

package main

import (
	"database/sql"
	_ "github.com/go-sql-driver/mysql"
	"log"
)

func main() {
	db, err := sql.Open("mysql",
		"root@tcp(127.0.0.1:3306)/hello")
	if err != nil {
		log.Fatal(err)
	}
	err = db.Ping()
	if err != nil {
		log.Fatal(err)
	}

	var (
		id   int
		name string
	)

	stmt, err := db.Prepare("select id, name from users where id = ?")
	if err != nil {
		log.Fatal(err)
	}
	defer stmt.Close()
	// stmt.QueryRowなら一行だけ取得する。
	err = stmt.QueryRow(1).Scan(&id, &name)
	log.Println(id, name)
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()
}

面倒なRowの扱いがなくなってスッキリしましたね。

INSERTとかUPDATEとかDELETEとか

package main

import (
	"database/sql"
	_ "github.com/go-sql-driver/mysql"
	"log"
)

func main() {
	db, err := sql.Open("mysql",
		"root@tcp(127.0.0.1:3306)/hello")
	defer db.Close()
	if err != nil {
		log.Fatal(err)
	}
	err = db.Ping()
	if err != nil {
		log.Fatal(err)
	}

	stmt, err := db.Prepare("INSERT INTO users(id, name) VALUES(?, ?)")
	if err != nil {
		log.Fatal(err)
	}
	res, err := stmt.Exec(2, "haruyama")
	if err != nil {
		log.Fatal(err)
	}
	lastId, err := res.LastInsertId()
	if err != nil {
		log.Fatal(err)
	}
	rowCnt, err := res.RowsAffected()
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("ID = %d, affected = %d\n", lastId, rowCnt)
}

とりあえず、INSERTでIDとnameを入れてみる例。 db.Execを使うとINSERT, UPDATE, DELETEが使える。

@yosuke-furukawa
Copy link
Author

トランザクション使う例とかもやりたかったけど、
タイムアップ。

後で追記するかも。

Tx.Exec等を使うらしい。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment