はじめに
ある程度C言語の基礎は身についてると自負しているので、いきなりDB接続してみた。
昔C#書いてたので割とすんなり理解できたと思う。
しかし、タイムスタンプの表示方法だけつまづいた。
やっぱタイム型は苦手だ。
実践!
MySQL
サンプルデータ作成
データベース作成
データベース名は任意で頼む!
CREATE DATABASE test_db;
テーブル作成
id(主キー)、名前、作成日時、更新日時
create table users (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
name varchar(10),
created_at datetime default current_timestamp,
updated_at timestamp default current_timestamp on update current_timestamp
);
サンプルデータ保存
INSERT INTO users (name) VALUES ("名前1"),("名前2"),("名前3");
Go!
go-sql-driverインストール
$ go get -u github.com/go-sql-driver/mysql
基本的に公式のコードそのままコピペで接続できる!
Goファイル編集
package main
import (
"database/sql"
"fmt"
"time"
_ "github.com/go-sql-driver/mysql"
)
type User struct {
ID int
Name string
Created_at time.Time
Updated_at time.Time
}
func main() {
db, err := sql.Open("mysql", "root:root@tcp(127.0.0.1:3306)/go_test?parseTime=true&loc=Asia%2FTokyo")
panic_err(err)
defer db.Close()
rows, err := db.Query("SELECT * FROM users")
panic_err(err)
defer rows.Close()
for rows.Next() {
var user User
err := rows.Scan(&user.ID, &user.Name, &user.Created_at, &user.Updated_at)
panic_err(err)
fmt.Println(user.ID, user.Name, user.Created_at, user.Updated_at)
}
err = rows.Err()
panic_err(err)
}
func panic_err(err error) {
if err != nil {
panic(err.Error())
}
}
エラーチェックの部分何回も同じこと書くのアレだったのでエラーチェック用の関数作ってます。
みんなちゃんと動いたかな?
解説
サーバー接続部分
db, err := sql.Open("mysql", "root:root@tcp(127.0.0.1:3306)/go_test?parseTime=true&loc=Asia%2FTokyo")
db, err := sql.Open("mysql", "ユーザー名:パスワード@tcp(ホスト:ポート)/データベース名?parseTime=true&loc=Asia%2FTokyo")
// ?parseTime=trueでタイムスタンプをtime型に変換してくれている。
// &loc=Asia%2FTokyoタイムゾーンを東京で表示。
defer
これ便利です!
呼び出し元の関数が終わるとき or returnされるときにdeferで書いた処理が走るみたいです。
今回は2箇所で使っています。
defer db.Close()
defer rows.Close()
ただし、defer db.Close()
を通った時点で、変数(今回はdb
)の値は確定します。
たとえその後に、db
の値が変わったとしてもdefer db.Close()
を通った時点の値が適用されます。
逆にdefer db.Close()
を通る前にdb
の値が変わるとそれが適用されます。
なので、処理の内容はdefer db.Close()
を通った時に確定し、実際に処理されるのは、呼び出し元の関数が終わるとき or returnされるときです。
今回で言うと最後のpanic_err(err)
の関数が終わった後に、発動します。
複数defer
を使ったときの処理される順番ですが、先に通るdefer db.Close()
が一番最後に処理され、defer rows.Close()
がその一つ前で処理されます。
func main() {
//中略
panic_err(err)
rows.Close()
db.Close()
}
deferで上の方に記述していてもこういう順番で処理されている。
select結果表示
for rows.Next() {
// 今回は上の方でuserの中身を定義しているが、ここでゴリゴリ書くこともできる。
var user User
// var id int
// var Name string
// var Created_at time.Time
// var Updated_at time.Timeみたいに。でもブサイクでしょ?
err := rows.Scan(&user.ID, &user.Name, &user.Created_at, &user.Updated_at)
if err != nil {
panic(err.Error())
}
fmt.Println(user.ID, user.Name, user.Created_at, user.Updated_at)
}
rows.Scan()内、最初idとnameだけ表示させようとしてidとnameしか記述していなかったらエラーになってしまった。
必ずselectしたすべてのカラムを読み込まないといけないらしい。
まとめ
今回はgo-sql-driverでMySQLに接続してみました。
次はGormで接続してみようかな。
Goのフレームワークといえばこれっていうやつあんのかな〜。
現場でどんな環境でGo言語開発してんのか気になる〜。