LoginSignup
1
0

【GO言語】mysqlへの接続でやらかしたこと

Posted at

やろうとしたこと

GO言語の公式チュートリアルのコードを基に(ほぼコピペ)ローカルのmysqlサーバに接続して、DBのデータを参照したり、書き込んだりするプログラムを書こうとしました。

書いたコード(エラー解消前)

以下、エラーが発生するコードです。

main.go
package main

import (
	"database/sql"
	"fmt"
	"log"

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

var db *sql.DB

type Album struct {
	ID     int64
	Title  string
	Artist string
	Price  float32
}

func albumByArtist(name string) ([]Album, error) {
	var albums []Album

	rows, err := db.Query("SELECT * FROM album WHERE artist = ?", name)

	if err != nil {
		return nil, fmt.Errorf("albumsByArtist %q: %v", name, err)
	}

	defer rows.Close()

	for rows.Next() {
		var alb Album
		err := rows.Scan(&alb.ID, &alb.Title, &alb.Artist, &alb.Price)
		if err != nil {
			return nil, fmt.Errorf("albumsByArtist %q: %v", name, err)
		}
		albums = append(albums, alb)
	}

	if err := rows.Err(); err != nil {
		return nil, fmt.Errorf("albumsByArtist %q: %v", name, err)
	}

	return albums, nil

}

func main() {
	//connect to DB
	cfg := mysql.Config{
		User:                 "user",
		Passwd:               "pass",
		Net:                  "tcp",
		Addr:                 "localhost:3306",
		DBName:               "recording",
		AllowNativePasswords: true,
	}

	//get a database handle
	var err error
	db, err := sql.Open("mysql", cfg.FormatDSN())

	if err != nil {
		log.Fatal(err)
	}

	pingErr := db.Ping()
	if pingErr != nil {
		log.Fatal(pingErr)
	}

	fmt.Println("connect to DB!")

	var albums []Album
	albums, err = albumByArtist("John Coltrane")

	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Albums found: %v\n", albums)

}

これを実行すると以下のエラーが発生します。
panic: runtime error: invalid memory address or nil pointer dereference

エラーの原因

かなり初歩的なミスでしたが、main()内のsql.Open()の書き方にミスがありました。

  • 正:db, err = sql.Open("mysql", cfg.FormatDSN())
  • 誤:db, err := sql.Open("mysql", cfg.FormatDSN())

=とすべきところ、うっかり:=と書いてしまったことが原因でした。

複数の関数内で共通のDBのコネクションを使うためグローバル変数として定義する必要があります。
ところが、main()内のsql.Open()を実行する際に:=としてしまうと、
左辺のdbはmain()内のローカル変数として定義されてしまいます。

そして、albumByArtist()内でDBにクエリを投げようと、グローバル変数のDBのコネクションを利用しようとしても、グローバル変数のコネクションがnilなので上記のエラーが発生したというわけです。
(当然main()内のコネクションにはデータが格納されています。)

最後に

GO言語を勉強したてで、意識して=:=の使い分けができていなかったため発生したエラーでした。
気をつけていきたいですね。

1
0
1

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
1
0