如果您的应用侧使用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 ( "github.com/go-sql-driver/mysql" )
2. 连接池初始化
在.go
文件的main方法中初始化连接池并配置以下参数,示例如下:
Addr // 创建一个数据库连接
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 db.Close()
// 设置连接池参数
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
表中写入数据为例演示。
方法一:直接写入数据
result, err := db.Exec("INSERT INTO userinfo (username, departname, created) VALUES (?, ?, ?)", "Linda", "Testing", "2016-06-21")
checkErr(err)
ids, err := result.LastInsertId()
fmt.Println(ids)
方法二:通过绑定参数的方式写入数据
stmt, err := db.Prepare("INSERT INTO userinfo SET username=?,departname=?,created=?")
res, err := stmt.Exec("James", "Research", "2016-06-17")
id, err := res.LastInsertId()
checkErr(err)
fmt.Println(id)
更新数据
本文以更新userinfo
表中的数据为例演示。
stmt, err = db.Prepare("UPDATE userinfo SET username=?, departname=?, created=? WHERE uid=?")
if err != nil {
// 如果准备语句时出现错误,则进行错误处理
}
res, err = stmt.Exec("Robert", "Sales", "2024-09-23", 2)
if err != nil {
fmt.Println(err)
}
rowCnt, _ := res.RowsAffected()
fmt.Println(rowCnt)
查询数据
本文以查询 userinfo
表中username=Linda
的数据为例演示。
方法一:直接查询数据
rows, err := db.Query("SELECT username,departname,created FROM userinfo WHERE username=?", "Linda")
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)
}
方法二:通过绑定参数的方式执行参数化查询
stmt, err = db.Prepare("SELECT username,departname,created FROM userinfo WHERE username=?")
if err != nil {
fmt.Println("prepare error", err)
return
}
rows, err = stmt.Query("Linda")
if err != nil {
fmt.Println("query data error", err)
return
}
defer rows.Close()
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)
}
删除数据
本文以删除userinfo
表中uid=1
的数据为例演示。
del_stmt, _ := db.Prepare("DELETE FROM userinfo WHERE uid=?")
del_stmt.Exec(1)
完整示例
package main
import (
"database/sql"
"fmt"
"github.com/go-sql-driver/mysql"
"time"
)
func main() {
//创建一个数据库连接
cfg := mysql.NewConfig()
cfg.User = "****"
cfg.Passwd = "****"
cfg.Net = "tcp"
cfg.Addr = "rm-2zefwjx1s8156******.mysql.rds.aliyuncs.com:3306"
cfg.DBName = "****"
conn, err := mysql.NewConnector(cfg)
if err != nil {
panic(err.Error())
}
db := sql.OpenDB(conn)
defer db.Close()
// 设置连接池参数
db.SetMaxOpenConns(20) // 设置连接池中最大打开的连接数
db.SetMaxIdleConns(2) // 设置连接池中最大空闲的连接数
db.SetConnMaxIdleTime(5 * time.Minute) // 设置连接在连接池中的最长的空闲时间
db.SetConnMaxLifetime(8 * time.Minute) // 设置连接的最大生命周期
checkErr(err)
_, 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("zhja", "研发", "2016-06-17")
id, err := res.LastInsertId()
checkErr(err)
fmt.Println(id)
result, err := db.Exec("INSERT INTO userinfo (username, departname, created) VALUES (?, ?, ?)", "lily", "销售", "2016-06-21")
checkErr(err)
ids, err := result.LastInsertId()
fmt.Println(ids)
del_stmt, _ := db.Prepare("DELETE FROM userinfo WHERE uid=?")
del_stmt.Exec(1)
stmt, err = db.Prepare("UPDATE userinfo SET username=?, departname=?, created=? WHERE uid=?")
if err != nil {
// 处理错误
}
res, err = stmt.Exec("lisi", "测试", "2024-09-23", 2)
if err != nil {
fmt.Println(err)
}
rowCnt, _ := res.RowsAffected()
fmt.Println(rowCnt)
rows, err := db.Query("SELECT username,departname,created FROM userinfo WHERE username=?", "lisi")
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)
}
stmt, err = db.Prepare("SELECT username,departname,created FROM userinfo WHERE username=?")
if err != nil {
fmt.Println("prepare error", err)
return
}
rows, err = stmt.Query("lisi")
if err != nil {
fmt.Println("query data error", err)
return
}
defer rows.Close()
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)
}
}
func checkErr(err error) {
if err != nil {
panic(err)
}
}
相关文档
RDS MySQL数据库代理中的连接池功能:设置RDS MySQL连接池