Web開発において、データベースの利用は必須ともいうべき技術です。
ECサイトやポータルサイト、会員制サイトや従量課金制のWebアプリケーションなど、データの検索や登録・修正が必要なプロダクトでのほとんどで使用されます。
そこで今回から2記事にわたり、GoプログラムからMySQLに接続し、基本的なデータ操作を行う実装を解説します。
さらにDB操作の基礎を身に着けた後は、実際にデータベースと連携してログイン機能やリスト機能などを実装していきたいと思います。
なお、当記事ではMySQLの環境構築については解説しませんので、MySQL環境をお持ちでない方は各位にて導入を行ってください。
Contents
GoにおけるDB接続インターフェース
Goはデータベース操作に関する標準機能として、database/sql/driverおよびdatabase/sqlパッケージを提供しています。
このうち、データベースドライバの役割を担うのはdatabase/sql/driverですが、これはデータベース接続のための標準的なインターフェース定義であり、MySQLやPostgerSQLなど特定のデータベースへの接続に最適化されたものではありません。
設計の意図としては、開発者がこの標準インターフェースを参照し、目的にあわせたデータベースドライバを開発することが想定されています。
とはいえ、既に有志によってDBエンジン別の有用なドライバが数多く作成されています。
よほど特別な事情がない限り、それらを借用すれば充分ですので、自前でドライバを実装するケースはほぼないでしょう。
MySQLドライバのインストール
それでは、MySQ接続用ドライバの外部パッケージをインストールしてみましょう。
MySQLをサポートしたドライバはいくつか存在しますが、今回は以下のMySQL用ドライバを採用したいと思います。
https://github.com/go-sql-driver/mysql
Windowsであればコマンドプロンプト、Macであればターミナルを起動し、以下のコマンドを実行してください。
GOPATHにgo-sql-driver/mysqlフォルダが作成されていればインストール成功です。
MySQLデータベースへの接続
それではGoプログラムからMySQLに接続してみましょう。
ここでは接続情報を以下の通りに定義しています。
- [ホスト名] localhost
- [ポート番号] 3306
- [データベース名] GO-TRAINING
- [文字コード]
- [ユーザ名] go-user
- [パスワード] gopass
サンプルコード
それでは先にサンプルを見てから解説を行いたいと思います。
コード内の接続情報は、環境にあわせて書き換えてください。
package main import ( "database/sql" "fmt" _ "github.com/go-sql-driver/mysql" ) func main() { // データベース接続 db, err := sql.Open("mysql", "go-user:gopass@tcp(localhost:3306)/GO-TRAINING?charset=utf8") if err != nil { fmt.Println(err.Error()) } // deferで処理終了前に必ず接続をクローズする defer db.Close() // 接続確認 err = db.Ping() if err != nil { fmt.Println("データベース接続失敗") return } else { fmt.Println("データベース接続成功!") } }
deferを使って接続直後にクローズ処理を記述している点に注目してください。
このコードの実行結果は以下の通りになります。
データベース接続成功!
sql.Open関数 ― データベースへの接続
12行目のsql.Open関数は、登録済みのデータベースドライバを開くために使用されます。
第1引数で、登録されているドライバを指定します。
データベースドライバの登録は、先ほどインストールしたgo-sql-driver/mysqlが行ってくれています。
第2引数では、go-sql-driverが定義する書式でデータベース接続情報を指定しています。
いくつかの書式がサポートされていますが、基本的には以下の書式を抑えておけば問題ないでしょう。
なお、ホスト名はlocalhost、ポート番号はデフォルトポートの3306であれば、省略が可能です。
したがって今回のサンプルでは、12行目を以下のように書き換えても問題なく接続できます。
db, err := sql.Open("mysql", "go-user:gopass@/GO-TRAINING?charset=utf8")
db.ping関数 ― 接続確認
sql.Open関数は、接続が無効であってもエラーを返しません。
接続指定したデータベースがアクセス可能な状態であるかを確認したい場合、db.Ping関数を使用します。
db.Ping関数は、対象のデータベースへの接続確認を行い、接続が行えない場合はerrorを返します。
試しに、接続情報の一部をわざと誤った内容に書き換えて実行してみましょう。
ここでは、ユーザ名をhoge-userに書き換えてみます。
db, err := sql.Open("mysql", "hoge-user:gopass@/GO-TRAINING?charset=utf8")
この状態でコードを実行すると、以下のようにdb.Pingのエラー処理が実行されます。
データベース接続失敗
接続情報を外部ファイルから読み込む
実際の開発では、データベースへの接続情報などは外部ファイルに記述することがほとんどでしょう。
前回の記事で解説した方法を利用し、JSON形式の設定ファイルに記述した接続情報を使用してデータベースへの接続を行う方法を解説します。
なお、JSON形式の設定ファイルについての詳細は以下の記事をご参照ください。
【Go入門】JSON形式で外部設定ファイルを作成・利用する方法
設定ファイルの作成
Goプログラムのディレクトリ内にconfディレクトリを作成し、その中に設定ファイルを配置します。
作成するファイルは、設定ファイルとなるdb.jsonと、設定ファイルを構造体にマッピングするためのdb.goです。
まず、db.goファイルに必要な接続情報のフィールドを持つ構造体を定義します。
さらに、設定ファイル内容を読み込んで構造体にマッピングする関数を記述します。
package conf // 独自の設定ファイルパッケージ import ( "encoding/json" "io/ioutil" ) // DB設定の構造体 type ConfDB struct { Host string `json:"host"` // ホスト名 Port int `json:"port"` // ポート番号 DbName string `json:"db-name"` // 接続先DB名 Charset string `json:"charset"` // 文字コード User string `json:"user"` // 接続ユーザ名 Pass string `json:"pass"` // 接続パスワード } // URL設定の構造体 func ReadConfDB() (*ConfDB, error) { // 設定ファイル名 const conffile = "conf/db.json" // 構造体を初期化 conf := new(ConfDB) // 設定ファイルを読み込む cValue, err := ioutil.ReadFile(conffile) if err != nil { return conf, err } // 読み込んだjson文字列をデコードし構造体にセット err = json.Unmarshal([]byte(cValue), conf) if err != nil { return conf, err } return conf, nil }
次に、db.jsonファイル内に接続情報を記述します。
接続情報の内容は環境にあわせてください。
{ "host": "localhost", "port": 3306, "db-name": "GO-TRAINING", "charset": "utf8", "user": "go-user", "pass": "gopass" }
設定ファイルの情報を使用して接続を行う
後は、主処理内で設定ファイルの設定値を使用して接続文字列を組み立てるだけです。
プラス演算子(+)で文字列連結してもよいですが、fmt.Sprintf関数を使用するとよりスマートに記述できます。
fmt.Sprintf関数の使用方法についてはこちらの記事をご参考ください。
【Go入門】fmtパッケージ ~ print系関数と書式指定
package main import ( "./conf" // 実装した設定パッケージの読み込み "database/sql" "fmt" _ "github.com/go-sql-driver/mysql" ) func main() { // 設定ファイルを読み込む confDB, err := conf.ReadConfDB() if err != nil { fmt.Println(err.Error()) } // 設定値から接続文字列を生成 conStr := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=%s", confDB.User, confDB.Pass, confDB.Host, confDB.Port, confDB.DbName, confDB.Charset) // データベース接続 db, err := sql.Open("mysql", conStr) if err != nil { fmt.Println(err.Error()) } // deferで処理終了前に必ず接続をクローズする defer db.Close() // 接続確認 err = db.Ping() if err != nil { fmt.Println("データベース接続失敗") return } else { fmt.Println("データベース接続成功!") } }
このコードを実行すると、先ほどと同様に正常にデータベースへの接続が行えます。
データベース接続成功!
これでメイン処理のコード内に接続情報をベタ書きしないでよくなりますね。
終わりに
今回はデータベース接続の導入として、ドライバのインストールと接続までの手順を解説しました。
題材としてMySQLを使用していますが、その他のDBエンジンを使用する場合でも、用途別のドライバをインストールするのだとご認識ください。
次回の記事では、実際にクエリを実行してデータの登録・更新・取得などを行ってみたいと思いますのであわせて学習してください。