お使いのアプリケーションが Go を使用しており、短期間の接続などのシナリオでデータベース接続を頻繁に作成する場合、または接続数が多く、ApsaraDB RDS for MySQL インスタンスの接続制限を超えている場合は、このチュートリアルを使用して Go-MySQL-Driver で接続できます。このドライバーは、接続の頻度を減らし、データベースのオーバーヘッドを最小限に抑えます。このトピックでは、接続後にデータベース操作を実行する方法についても説明します。
Go-MySQL-Driver は、MySQL および MariaDB データベースへの接続をサポートする Go 用のサードパーティデータベースドライバーです。詳細については、「Go-MySQL-Driver」をご参照ください。
制限事項
このガイドは、MySQL 5.7、8.0、または 8.4 を実行する ApsaraDB RDS for MySQL インスタンスに適用されます。
前提条件
-
Go 環境をダウンロードしてインストール済みであること。Go 1.20 以降を推奨します。
-
クライアントの IP アドレスを ApsaraDB RDS for MySQL インスタンスの IP ホワイトリストに追加してください。詳細については、「IP ホワイトリストの設定」をご参照ください。
説明お使いのアプリケーションが、ApsaraDB RDS for MySQL インスタンスと同じリージョンおよび仮想プライベートクラウド (VPC) 内にある Elastic Compute Service (ECS) インスタンスにデプロイされている場合は、IP ホワイトリストを設定する必要はありません。
Go-MySQL-Driver を使用したデータベースへの接続
ステップ1:依存関係の追加
-
Go プロジェクトの
go.modファイルに、go-sql-driver依存関係を追加します。require ( github.com/go-sql-driver/mysql v1.8.1 ) -
.goファイルに、次のパッケージをインポートしてください。import ( // 汎用的なSQLインターフェースを提供します。 "database/sql" // フォーマットされたI/Oを実装します。 "fmt" // Go で MySQL データベースに接続して操作するためのドライバーです。 "github.com/go-sql-driver/mysql" // 時間の測定と表示機能を提供します。 "time" )
ステップ2:接続プールの初期化
.go ファイルの main 関数で、接続プールを初期化し、次のパラメーターを設定してください。以下にコード例を示します。
// データベース接続を作成します。
cfg := mysql.NewConfig()
cfg.User = "****" // 実際のデータベースのユーザー名に置き換えてください。
cfg.Passwd = "****" // 実際のデータベースのパスワードに置き換えてください。
cfg.Net = "tcp" // 接続タイプはTCPです。デフォルト値のままにしてください。
cfg.Addr = "rm-2zefwjx1s8156******.mysql.rds.aliyuncs.com:3306" // MySQL データベースの実際のエンドポイントとポートに置き換えてください。
cfg.DBName = "****" // 実際のデータベース名に置き換えてください。
conn, err := mysql.NewConnector(cfg)
if err != nil {
panic(err.Error())
}
db := sql.OpenDB(conn)
defer func(db *sql.DB) {
err := db.Close()
if err != nil {
fmt.Printf("データベース接続のクローズ中にエラーが発生しました: %v\n", err)
}
}(db)
// 接続プールのパラメーターを設定します。
db.SetMaxOpenConns(20) // 接続プール内のオープン接続の最大数を設定します。必要に応じてこの値を調整してください。
db.SetMaxIdleConns(2) // 接続プール内のアイドル接続の最大数を設定します。必要に応じてこの値を調整してください。
db.SetConnMaxIdleTime(10 * time.Second) // プール内の接続の最大アイドル時間を設定します。必要に応じてこの値を調整してください。
db.SetConnMaxLifetime(80 * time.Second) // 接続の最大生存期間を設定します。必要に応じてこの値を調整してください。
ApsaraDB RDS for MySQL インスタンスのエンドポイントとポートを確認するには、「インスタンスのエンドポイントとポートの表示と管理」をご参照ください。
主要な接続プールパラメーター
-
推奨設定 はデータベースの安定性を向上させ、運用リスクを低減します。任意設定 はパフォーマンスを向上させることができます。
-
本番環境で新しいパラメーター値を適用する前に、包括的な機能テストとパフォーマンステストを実行して、システムの安定性を確認してください。
推奨
|
パラメーター |
説明 |
デフォルト |
推奨 |
説明 |
|
|
接続がアイドル状態でいられる最大時間。 |
0 |
10~30分 |
|
|
|
接続を使用できる最大時間。 |
0 |
1~8時間 |
|
|
|
データベースへのオープン接続の最大数。 |
0 |
100 |
|
|
|
プールに保持するアイドル接続の最大数。 |
2 |
20 |
|
|
|
I/O 読み取りタイムアウト。 |
0 |
10000 ms~60000 ms |
|
|
|
I/O 書き込みタイムアウト。 |
0 |
10000 ms~60000 ms |
|
任意
|
パラメーター |
説明 |
デフォルト |
推奨 |
説明 |
|
|
接続を確立するためのタイムアウト。 |
デフォルト値はオペレーティングシステムによって決定されます。 |
3000 ms |
|
データベース操作の実行
テーブルの作成
この例では、userinfo という名前のテーブルを作成する方法を説明します。
_, err = db.Exec("CREATE TABLE IF NOT EXISTS userinfo(uid INT AUTO_INCREMENT, username VARCHAR(20) NOT NULL DEFAULT '', departname VARCHAR(20) NOT NULL DEFAULT '', created VARCHAR(10) NOT NULL DEFAULT '', PRIMARY KEY(uid));")
if err != nil {
fmt.Println("create table error: ", err)
return
}
データの挿入
この例では、userinfo テーブルにデータを挿入する方法を説明します。
方法1: db.Prepare の使用
stmt, err := db.Prepare("INSERT userinfo SET username=?,departname=?,created=?")
res, err := stmt.Exec("田中一郎", "研究", "2016-06-17")
id, err := res.LastInsertId()
if err != nil {
panic(err)
}
fmt.Println(id)
方法2: db.Exec の使用
result, err := db.Exec("INSERT INTO userinfo (username, departname, created) VALUES (?, ?, ?)", "鈴木花子", "テスト", "2016-06-21")
if err != nil {
panic(err)
}
ids, err := result.LastInsertId()
fmt.Println(ids)
データの更新
この例では、userinfo テーブルのデータを更新する方法を説明します。
stmtUpdate, err := db.Prepare("UPDATE userinfo SET username=?, departname=?, created=? WHERE username=?")
if err != nil {
fmt.Println("Prepare update statement error:", err)
return
}
resUpdate, err := stmtUpdate.Exec("佐藤健太", "営業", "2024-09-23", "鈴木花子")
if err != nil {
fmt.Println(err)
}
rowCnt, _ := resUpdate.RowsAffected()
fmt.Println(rowCnt)
データのクエリ
この例では、userinfo テーブルから username='佐藤健太' のデータをクエリする方法を説明します。
方法1: db.Query の使用
rows, err := db.Query("SELECT username,departname,created FROM userinfo WHERE username=?", "佐藤健太")
if err != nil {
panic(err)
}
for rows.Next() {
var username, departname, created string
if err := rows.Scan(&username, &departname, &created); err != nil {
fmt.Println(err)
}
fmt.Println("username:", username, "departname:", departname, " created:", created)
}
defer func(rows *sql.Rows) {
err := rows.Close()
if err != nil {
fmt.Println(err)
}
}(rows)
方法2: db.Prepare の使用
stmtQuery, err := db.Prepare("SELECT username,departname,created FROM userinfo WHERE username=?")
if err != nil {
fmt.Println("prepare error", err)
return
}
rowData, err := stmtQuery.Query("佐藤健太")
if err != nil {
fmt.Println("query data error", err)
return
}
for rowData.Next() {
var username, departname, created string
if err := rowData.Scan(&username, &departname, &created); err != nil {
fmt.Println(err)
}
fmt.Println("username:", username, "departname:", departname, "created:", created)
}
defer func(rows *sql.Rows) {
err := rows.Close()
if err != nil {
fmt.Println(err)
}
}(rowData)
データの削除
この例では、userinfo テーブルから username='田中一郎' のデータを削除する方法を説明します。
delStmt, _ := db.Prepare("DELETE FROM userinfo WHERE username=?")
resultDel, err := delStmt.Exec("田中一郎")
if err != nil {
panic(err)
}
rowAffect, _ := resultDel.RowsAffected()
fmt.Println("データの削除が完了しました。", rowAffect)
完全な例
package main
import (
// 汎用的なSQLインターフェースを提供します。
"database/sql"
// フォーマットされたI/Oを実装します。
"fmt"
// Go で MySQL データベースに接続して操作するためのドライバーです。
"github.com/go-sql-driver/mysql"
// 時間の測定と表示機能を提供します。
"time"
)
func main() {
// データベース接続を作成します。
cfg := mysql.NewConfig()
cfg.User = "****" // ユーザー名
cfg.Passwd = "****" // パスワード
cfg.Net = "tcp" // 接続タイプ
cfg.Addr = "rm-2ze1vw17v542q6b****.mysql.pre.rds.aliyuncs.com:3306" // エンドポイント
cfg.DBName = "****" // データベース名
cfg.Timeout = 3 * time.Second // 接続を確立するためのタイムアウト。
cfg.ReadTimeout = 60 * time.Second // I/O 読み取りタイムアウト。
cfg.WriteTimeout = 60 * time.Second // I/O 書き込みタイムアウト。
conn, err := mysql.NewConnector(cfg)
if err != nil {
panic(err.Error())
}
db := sql.OpenDB(conn)
defer func(db *sql.DB) {
err := db.Close()
if err != nil {
fmt.Printf("データベース接続のクローズ中にエラーが発生しました: %v\n", err)
}
}(db)
// 接続プールのパラメーターを設定します。
db.SetMaxOpenConns(100) // オープン接続の最大数。
db.SetMaxIdleConns(20) // アイドル接続の最大数。
db.SetConnMaxIdleTime(10 * time.Minute) // 接続の最大アイドル時間。
db.SetConnMaxLifetime(8 * time.Hour) // 接続の最大生存期間。
// userinfo という名前のテーブルを作成します。
_, err = db.Exec("CREATE TABLE IF NOT EXISTS userinfo(uid INT AUTO_INCREMENT, username VARCHAR(20) NOT NULL DEFAULT '', departname VARCHAR(20) NOT NULL DEFAULT '', created VARCHAR(10) NOT NULL DEFAULT '', PRIMARY KEY(uid));")
if err != nil {
fmt.Println("create table error: ", err)
return
}
// プリペアドステートメントでデータを挿入します。
stmt, err := db.Prepare("INSERT userinfo SET username=?,departname=?,created=?")
res, err := stmt.Exec("田中一郎", "研究", "2016-06-17")
id, err := res.LastInsertId()
if err != nil {
panic(err)
}
fmt.Println(id)
// 直接実行でデータを挿入します。
result, err := db.Exec("INSERT INTO userinfo (username, departname, created) VALUES (?, ?, ?)", "鈴木花子", "テスト", "2016-06-21")
if err != nil {
panic(err)
}
ids, err := result.LastInsertId()
fmt.Println(ids)
// データを更新します。
stmtUpdate, err := db.Prepare("UPDATE userinfo SET username=?, departname=?, created=? WHERE username=?")
if err != nil {
fmt.Println("Prepare update statement error:", err)
return
}
resUpdate, err := stmtUpdate.Exec("佐藤健太", "営業", "2024-09-23", "鈴木花子")
if err != nil {
fmt.Println(err)
}
rowCnt, _ := resUpdate.RowsAffected()
fmt.Println(rowCnt)
// データを直接クエリします。
rows, err := db.Query("SELECT username,departname,created FROM userinfo WHERE username=?", "佐藤健太")
if err != nil {
panic(err)
}
for rows.Next() {
var username, departname, created string
if err := rows.Scan(&username, &departname, &created); err != nil {
fmt.Println(err)
}
fmt.Println("username:", username, "departname:", departname, "created:", created)
}
defer func(rows *sql.Rows) {
err := rows.Close()
if err != nil {
fmt.Println(err)
}
}(rows)
// プリペアドステートメントでデータをクエリします。
stmtQuery, err := db.Prepare("SELECT username,departname,created FROM userinfo WHERE username=?")
if err != nil {
fmt.Println("prepare error", err)
return
}
rowData, err := stmtQuery.Query("佐藤健太")
if err != nil {
fmt.Println("query data error", err)
return
}
for rowData.Next() {
var username, departname, created string
if err := rowData.Scan(&username, &departname, &created); err != nil {
fmt.Println(err)
}
fmt.Println("username:", username, "departname:", departname, "created:", created)
}
defer func(rows *sql.Rows) {
err := rows.Close()
if err != nil {
fmt.Println(err)
}
}(rowData)
// データを削除します。
delStmt, _ := db.Prepare("DELETE FROM userinfo WHERE username=?")
resultDel, err := delStmt.Exec("田中一郎")
if err != nil {
panic(err)
}
rowAffect, _ := resultDel.RowsAffected()
fmt.Println("データの削除が完了しました。", rowAffect)
}