0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

GolangでMysqlに接続してみた!

Last updated at Posted at 2021-06-13

はじめに

ある程度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ファイル編集

dbconnect.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言語開発してんのか気になる〜。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?