如果您的應用側使用Go語言,且資料庫連接建立頻繁(例如短串連情境)或串連數量較大(大於MySQL資料庫的串連數限制),您可以參考本教程通過Go驅動包Go-MySQL-Driver串連RDS MySQL資料庫,降低串連建立頻率以減少資料庫主線程的開銷。此外,本文還提供串連後操作RDS MySQL資料庫的方法。
Go-MySQL-Driver為Go語言的第三方資料庫驅動包,支援串連MySQL與MariaDB資料庫,詳情請參見Go-MySQL-Driver。
使用限制
RDS MySQL執行個體的資料庫版本僅支援5.7、8.0。
準備工作
使用Go-MySQL-Driver串連資料庫
1. 依賴引入
在Go專案的
go.mod
檔案中,添加go-sql-driver
依賴:require ( github.com/go-sql-driver/mysql v1.8.1 )
在
.go
檔案中匯入如下包:import ( // 引入Go語言的 database/sql 包,它提供了通用的SQL介面 "database/sql" // 引入fmt包,它是Go語言標準庫中用于格式化輸入輸出的包 "fmt" // 該驅動可在Go語言中串連和操作MySQL資料庫 "github.com/go-sql-driver/mysql" // 引入了Go語言的time包,用於處理時間相關的操作 "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("Error closing database connection: %v\n", err)
}
}(db)
// 設定串連池參數
db.SetMaxOpenConns(20) // 設定串連池中最大開啟的串連數,您可根據實際需要手動調整
db.SetMaxIdleConns(2) // 設定串連池中最大閒置串連數,您可根據實際需要手動調整
db.SetConnMaxIdleTime(10 * time.Second) // 串連在串連池中的最長的空閑時間,您可根據實際需要手動調整
db.SetConnMaxLifetime(80 * time.Second) // 設定串連的最大生命週期,您可根據實際需要手動調整
RDS MySQL資料庫連接地址和連接埠的擷取方法,請參見查看和管理執行個體串連地址和連接埠。
附錄:串連池關鍵參數配置
推薦配置“推薦配置的參數”模組,降低資料庫運行風險;您可以選擇性配置“可選擇配置的參數模組”,以提升使用效能。
為了最大程度地避免潛在的風險和不確定性,您在將新的參數值用於生產環境前,建議至少進行一輪完整的功能測試和效能測試,以確保系統穩定性和可靠性。
參數名 | 含義 | 預設值 | 推薦值 | 說明 |
maxIdleTime | 設定最大空閑時間(單位:分鐘)。 | 0 | 10~30 |
|
maxLifetime | 設定串連的生命週期時間(單位:小時)。 | 0 | 1~8 |
|
maxOpen | 設定串連池中允許的最大串連數。 | 0 | 100 |
|
maxIdleCount | 設定串連池中允許的最大空閑串連數。 | 2 | 20 |
|
readTimeout | I/O讀取的逾時時間,您可按需指定為毫秒(ms)、秒(s)或分鐘(m)。 | 0 | 10000ms-60000ms |
|
writeTimeout | I/O寫入的逾時時間,您可按需指定為毫秒(ms)、秒(s)或分鐘(m)。 | 0 | 10000ms-60000ms |
|
參數名 | 含義 | 預設值 | 推薦值 | 說明 |
timeout | 串連建立的逾時時間,您可按需指定為毫秒(ms)、秒(s)或分鐘(m)。 | 預設值是根據作業系統的預設值來設定。 | 3000ms |
|
操作資料庫
建立表
本文以建立一個名為 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
表中寫入資料為例示範。
stmt, err := db.Prepare("INSERT userinfo SET username=?,departname=?,created=?")
res, err := stmt.Exec("James", "Research", "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 (?, ?, ?)", "Linda", "Testing", "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("Robert", "Sales", "2024-09-23", "Linda")
if err != nil {
fmt.Println(err)
}
rowCnt, _ := resUpdate.RowsAffected()
fmt.Println(rowCnt)
查詢資料
本文以查詢 userinfo
表中username=Robert
的資料為例示範。
rows, err := db.Query("SELECT username,departname,created FROM userinfo WHERE username=?", "Robert")
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("Robert")
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=James
的資料為例示範。
delStmt, _ := db.Prepare("DELETE FROM userinfo WHERE username=?")
resultDel, err := delStmt.Exec("James")
if err != nil {
panic(err)
}
rowAffect, _ := resultDel.RowsAffected()
fmt.Println("Data deletion completed.", rowAffect)
完整樣本
package main
import (
// 引入Go語言的 database/sql 包,它提供了通用的SQL介面
"database/sql"
// 引入fmt包,它是Go語言標準庫中用于格式化輸入輸出的包
"fmt"
// 該驅動可在Go語言中串連和操作MySQL資料庫
"github.com/go-sql-driver/mysql"
// 引入了Go語言的time包,用於處理時間相關的操作
"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 /*串連到資料庫的逾時時間,您可按需指定為毫秒(ms)、秒(s)或分鐘(m)*/
cfg.ReadTimeout = 60 * time.Second /*I/O讀取的逾時時間,您可按需指定為毫秒(ms)、秒(s)或分鐘(m)*/
cfg.WriteTimeout = 60 * time.Second /*I/O寫入的逾時時間,您可按需指定為毫秒(ms)、秒(s)或分鐘(m)*/
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("Error closing database connection: %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("James", "Research", "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 (?, ?, ?)", "Linda", "Testing", "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("Robert", "Sales", "2024-09-23", "Linda")
if err != nil {
fmt.Println(err)
}
rowCnt, _ := resUpdate.RowsAffected()
fmt.Println(rowCnt)
// 直接查詢資料
rows, err := db.Query("SELECT username,departname,created FROM userinfo WHERE username=?", "Robert")
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("Robert")
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("James")
if err != nil {
panic(err)
}
rowAffect, _ := resultDel.RowsAffected()
fmt.Println("Data deletion completed.", rowAffect)
}
相關文檔
RDS MySQL資料庫代理中的串連池功能:設定RDS MySQL串連池