第32章:连接池与数据库配置优化
本章目标
学完本章后,你将能够:
- 理解
sql.DB连接池的工作原理 - 根据业务需求配置连接池参数
- 监控连接池状态
- 排查连接泄漏问题
前置知识
- 需要先学习:第03章(连接数据库)
- 需要了解:TCP 连接基本概念
32.1 连接池原理
┌──────────┐
│ Go App │
└────┬─────┘
│
┌─────────▼─────────┐
│ 连接池 (sql.DB) │
│ │
│ ┌────┐ ┌────┐ │
│ │空闲│ │空闲│ │ ← MaxIdleConns = 2
│ └────┘ └────┘ │
│ ┌────┐ ┌────┐ │
│ │使用│ │使用│ │ ← 正在执行查询
│ └────┘ └────┘ │
│ │ ← MaxOpenConns = 4
└─────────┬──────────┘
│
┌─────────▼──────────┐
│ MySQL 服务器 │
└────────────────────┘32.2 四个核心参数
go
sqlDB, _ := db.DB()
// 1. 最大打开连接数(默认:无限!)
sqlDB.SetMaxOpenConns(25)
// 2. 最大空闲连接数(默认:2)
sqlDB.SetMaxIdleConns(10)
// 3. 连接最大存活时间(默认:永久)
sqlDB.SetConnMaxLifetime(5 * time.Minute)
// 4. 空闲连接最大存活时间(Go 1.15+)
sqlDB.SetConnMaxIdleTime(1 * time.Minute)| 参数 | 默认值 | 推荐值 | 为什么 |
|---|---|---|---|
| MaxOpenConns | 无限 | 25-100 | 防止连接数爆炸 |
| MaxIdleConns | 2 | ~10 | 保留热连接,减少握手 |
| ConnMaxLifetime | 永久 | < MySQL wait_timeout | 防止 MySQL 断开连接 |
| ConnMaxIdleTime | 永久 | 1-5 分钟 | 及时释放空闲连接 |
32.3 连接池监控
go
stats := sqlDB.Stats()
fmt.Printf("连接池状态:\n")
fmt.Printf(" 最大打开: %d\n", stats.MaxOpenConnections)
fmt.Printf(" 当前打开: %d\n", stats.OpenConnections) // 已建立的连接
fmt.Printf(" 使用中: %d\n", stats.InUse) // 正在执行查询
fmt.Printf(" 空闲: %d\n", stats.Idle) // 空闲待命
fmt.Printf(" 等待数: %d\n", stats.WaitCount) // 等待连接的请求数
fmt.Printf(" 等待时长: %v\n", stats.WaitDuration)32.4 连接泄漏排查
连接泄漏是指连接被打开但没有正确释放:
go
// ❌ 连接泄漏
rows, _ := db.Raw("SELECT * FROM big_table").Rows()
for rows.Next() { ... }
// 忘记 rows.Close() → 连接永不归还
// ✅ 正确释放
rows, _ := db.Raw("SELECT * FROM big_table").Rows()
defer rows.Close()
for rows.Next() { ... }32.5 实战:生产级连接池
go
func InitDB(dsn string) (*gorm.DB, error) {
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
SkipDefaultTransaction: true,
PrepareStmt: true,
Logger: logger.Default.LogMode(logger.Warn),
})
if err != nil {
return nil, err
}
sqlDB, _ := db.DB()
// 根据服务器规格配置
sqlDB.SetMaxOpenConns(50) // 4核服务器推荐 25-50
sqlDB.SetMaxIdleConns(15) // 约为 MaxOpenConns 的 1/3
sqlDB.SetConnMaxLifetime(3 * time.Minute) // 小于 MySQL wait_timeout(8h)
sqlDB.SetConnMaxIdleTime(1 * time.Minute) // 及时回收空闲
return db, nil
}本章小结
- 四个参数:MaxOpenConns、MaxIdleConns、ConnMaxLifetime、ConnMaxIdleTime
sqlDB.Stats()监控连接池状态- 连接泄漏:忘记
rows.Close()或defer - 生产环境必须配置连接池上限
练习题
- 配置一个连接池(MaxOpen=25, MaxIdle=10, MaxLifetime=5min),然后用 Stats() 监控状态。
- 写一段会泄漏连接的代码,然后用 Stats() 观察到连接数不下降。
- 修复上一题的连接泄漏。
- (思考题)为什么 MaxOpenConns 默认是"无限制"?这是设计缺陷还是有意为之?