Go言語でデータベース(MySQL)に接続する方法

Go言語

Go言語でデータベースに接続するための方法について紹介します。
今回はMySQLを利用します。

Go言語でデータベースへ接続する手順

  1. データベース接続のパッケージをインポート
  2. 接続するデータベースのドライバをインポート
  3. データベースのオープン

以下では各手順について紹介します。

データベース接続のパッケージをインポート

データベースに接続するためのパッケージをインポートします。
Go言語の標準パッケージではdatabase/sqlが該当します。

import "database/sql"

接続するデータベースのドライバをインポート

データベースに接続するにはドライバが必要です。ドライバはデータベースの種類ごとに用意されています。
たとえばMySQLの場合はgithub.com/go-sql-driver/mysqlが該当します。

ドライバのパッケージは直接コード上で利用しないのでアンダースコア(_)でインポートします。(blank identifier

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

各種データベースのドライバはこちらで確認ができます。

データベースのオープン

データベースへアクセスするためのオブジェクトを作成します。
database/sqlの場合、Open関数を利用してdb, err := sql.Open("ドライバ名", "接続文字列")のようにすると変数dbを通じてデータベースへアクセスできます。

"接続文字列"は各種ドライバのドキュメントを参考に記載します。MySQLの場合はこちらににフォーマットが記載されています。

動作確認

実際にGo言語からデータベースに接続してみます。

下準備: 検証用のデータベースをDockerで用意する

今回はMySQLのDockerイメージを利用して検証用のデータベースを構築します。

データベース接続情報
  • ユーザー名: webuser
  • パスワード: webpass
  • データベース名: go_mysql8_development
  • ポート: 3306

docker-compose.yml

version: '3'
services:
  db:
    image: mysql:8.0.21
    ports:
      - '3306:3306'
    command: --default-authentication-plugin=mysql_native_password
    environment:
      MYSQL_USER: 'webuser'
      MYSQL_PASSWORD: 'webpass'
      MYSQL_ROOT_PASSWORD: 'pass'
      MYSQL_DATABASE: 'go_mysql8_development'

docker-compose.ymlでコンテナ起動後、以下のようにデータベースに接続できればOKです。

### コンテナの起動
$ cd /path/to/docker-compose-file
$ docker-compose up -d

### dbコンテナにアクセスし、データベースがあることを確認
$ docker-compose exec db mysql -uwebuser -pwebpass -D go_mysql8_development -e "show databases"

+-----------------------+
| Database              |
+-----------------------+
| go_mysql8_development |
| information_schema    |
+-----------------------+

サンプルコードの実装と実行

最終的なサンプルコードは以下のようになります。

sql.Openはあくまでデータベースへ接続するオブジェクトを生成しているだけです。
ですので、実際のデータベースへの接続テストはdb.Ping()で確認します。

main.go

package main

import (
    "database/sql"
    "fmt"

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

func main() {
    // [ユーザ名]:[パスワード]@tcp([ホスト名]:[ポート番号])/[データベース名]?charset=[文字コード]
    dbconf := "webuser:webpass@tcp(127.0.0.1:3306)/go_mysql8_development?charset=utf8mb4"

    db, err := sql.Open("mysql", dbconf)

    // 接続が終了したらクローズする
    defer db.Close()  

    if err != nil {
        fmt.Println(err.Error())
    }

    err = db.Ping()

    if err != nil {
        fmt.Println("データベース接続失敗")
        return
    } else {
        fmt.Println("データベース接続成功")
    }
}

サンプルコードを実行し、以下のように『データベース接続成功』の文字列が表示されればOKです。

### 作業ディレクトリへ移動
$ cd /path/to/project

### パッケージのインストール
$ go mod init example
$ go mod tidy

### 実行
$ go run main.go

データベース接続成功

参考: データベース接続のソースコードをリファクタリングする

上記で紹介したソースコードは以下の改善点があります。

  • データベース接続のロジックがmain関数に直接書かれている
  • データベース情報がソースコードにベタ書きされている

ここからはソースコードのリファクタリング方法について紹介します。

データベース接続のロジックを別パッケージ化する

データベース接続のロジックを別パッケージにすることでmain関数をシンプルにします。

main.go

package main

import (
+ "example/database" // "モジュール名/パッケージ名"
  "fmt"
- "database/sql"
-   _ "github.com/go-sql-driver/mysql"
)

func main() {

+ db := database.Connect()
- dbconf := "webuser:webpass@tcp(127.0.0.1:3306)/go_mysql8_development?charset=utf8mb4"
-
- db, err := sql.Open("mysql", dbconf)
- if err != nil {
-   fmt.Println(err.Error())
- }

  defer db.Close()

  err := db.Ping()

  if err != nil {
    fmt.Println("データベース接続失敗")
    return
  } else {
    fmt.Println("データベース接続成功")
  }
}

データベース接続に関するパッケージは以下の通りです。
外部パッケージから呼び出せるようにするため、関数名は大文字から始めます。

database/connect.go

package database

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

func Connect() *sql.DB {

    user := "webuser"
    password := "webpass"
    host := "localhost"
    port := "3306"
    database_name := "go_mysql8_development"

    dbconf := user + ":" + password + "@tcp(" + host + ":" + port + ")/" + database_name + "?charset=utf8mb4"
    db, err := sql.Open("mysql", dbconf)
    if err != nil {
        fmt.Println(err.Error())
    }
    return db
}

GoDotEnvを導入してデータベース接続情報を.envファイルに配置する

GoDotEnvはGo言語で.envファイルを利用できるようにするパッケージです。
GoDotEnvを利用することでデータベース接続情報を環境変数に置き換えられます。

GoDotEnvはgodotenv.Load()で環境変数をロードし、os.Getenv("Key名")で値を呼び出します。
GoDotEnvを利用したdatabaseパッケージのソースコードは以下の通りです。

.env

DB_USER=webuser
DB_PASSWORD=webpass
DB_HOST=db
DB_PORT=3306
DB_DATABASE_NAME=go_mysql8_development

database/connect.go

package database

import (
    "database/sql"
    "fmt"
    "os"

    "github.com/joho/godotenv"

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

func Connect() *sql.DB {
    err := godotenv.Load()
    if err != nil {
        fmt.Println(err.Error())
    }

    user := os.Getenv("DB_USER")
    password := os.Getenv("DB_PASSWORD")
    host := os.Getenv("DB_HOST")
    port := os.Getenv("DB_PORT")
    database_name := os.Getenv("DB_DATABASE_NAME")

    dbconf := user + ":" + password + "@tcp(" + host + ":" + port + ")/" + database_name + "?charset=utf8mb4"
    db, err := sql.Open("mysql", dbconf)
    if err != nil {
        fmt.Println(err.Error())
    }
    return db
}

最終的なソースコード

リファクタリングを終えた最終的なソースコードは以下の通りです。

main.go

package main

import (
    "example/database"
    "fmt"
)

func main() {
    db := database.Connect()
    defer db.Close()

    err := db.Ping()

    if err != nil {
        fmt.Println("データベース接続失敗")
        return
    } else {
        fmt.Println("データベース接続成功")
    }
}

database/connect.go

package database

import (
    "database/sql"
    "fmt"
    "os"

    "github.com/joho/godotenv"

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

func Connect() *sql.DB {
    err := godotenv.Load()
    if err != nil {
        fmt.Println(err.Error())
    }

    user := os.Getenv("DB_USER")
    password := os.Getenv("DB_PASSWORD")
    host := os.Getenv("DB_HOST")
    port := os.Getenv("DB_PORT")
    database_name := os.Getenv("DB_DATABASE_NAME")

    dbconf := user + ":" + password + "@tcp(" + host + ":" + port + ")/" + database_name + "?charset=utf8mb4"

    db, err := sql.Open("mysql", dbconf)
    if err != nil {
        fmt.Println(err.Error())
    }
    return db
}

.env

DB_USER=webuser
DB_PASSWORD=webpass
DB_HOST=db
DB_PORT=3306
DB_DATABASE_NAME=go_mysql8_development

まとめ

Go言語でデータベースに接続する方法
  1. データベース接続のパッケージをインポート
  2. 接続するデータベースのドライバをインポート
  3. データベース接続情報をドライバのパラメータに渡す
  4. データベースをオープンし、オブジェクトを生成
  5. オブジェクトを通じてデータベースを操作する

Twitter(@nishina555)やってます。フォローしてもらえるとうれしいです!