如果您的应用侧使用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连接池