核心概念与准备工作
数据库驱动是Go语言操作数据库的基础,标准库database/sql
提供了通用接口,实际连接需要特定数据库驱动。主流选择包括:
– MySQL: github.com/go-sql-driver/mysql
– PostgreSQL: github.com/lib/pq
– SQLite: github.com/mattn/go-sqlite3
安装驱动示例:
go get -u github.com/go-sql-driver/mysql
基础连接与CRUD操作
建立连接池
Go通过sql.Open()
初始化连接池而非单一连接,重要参数包括:
– MaxOpenConns
: 最大打开连接数(默认无限制)
– MaxIdleConns
: 最大空闲连接数(默认2)
– ConnMaxLifetime
: 连接最大存活时间
package main
import (
"database/sql"
"log"
_ "github.com/go-sql-driver/mysql"
)
func main() {
dsn := "user:password@tcp(127.0.0.1:3306)/dbname?parseTime=true"
db, err := sql.Open("mysql", dsn)
if err != nil {
log.Fatal(err)
}
defer db.Close()
db.SetMaxOpenConns(25)
db.SetMaxIdleConns(25)
db.SetConnMaxLifetime(5 * time.Minute)
if err := db.Ping(); err != nil {
log.Fatal("Connection test failed:", err)
}
}
执行基础查询
使用Query()
获取多行结果,QueryRow()
获取单行:
type User struct {
ID int
Name string
Email string
}
func getUsers(db *sql.DB) ([]User, error) {
rows, err := db.Query("SELECT id, name, email FROM users WHERE active = ?", true)
if err != nil {
return nil, err
}
defer rows.Close()
var users []User
for rows.Next() {
var u User
if err := rows.Scan(&u.ID, &u.Name, &u.Email); err != nil {
return nil, err
}
users = append(users, u)
}
return users, rows.Err()
}
高级特性与优化
预处理语句
使用Prepare()
创建预处理语句可提升重复查询性能:
func bulkInsert(db *sql.DB, users []User) error {
stmt, err := db.Prepare("INSERT INTO users(name, email) VALUES(?, ?)")
if err != nil {
return err
}
defer stmt.Close()
for _, u := range users {
if _, err := stmt.Exec(u.Name, u.Email); err != nil {
return err
}
}
return nil
}
事务处理
ACID事务示例:
func transferFunds(db *sql.DB, from, to int, amount float64) error {
tx, err := db.Begin()
if err != nil {
return err
}
defer func() {
if p := recover(); p != nil {
tx.Rollback()
panic(p)
}
}()
if _, err := tx.Exec(
"UPDATE accounts SET balance = balance - ? WHERE id = ?",
amount, from,
); err != nil {
tx.Rollback()
return err
}
if _, err := tx.Exec(
"UPDATE accounts SET balance = balance + ? WHERE id = ?",
amount, to,
); err != nil {
tx.Rollback()
return err
}
return tx.Commit()
}
ORM与原生SQL的抉择
原生SQL优势
- 精确控制查询逻辑
- 避免ORM转换开销
- 复杂查询更直观
ORM适用场景
- 快速原型开发
- 简单CRUD操作
- 数据库无关设计
推荐库:
– gorm.io/gorm
: 全功能ORM
– github.com/jmoiron/sqlx
: 轻量级扩展
// SQLx示例
var users []struct {
ID int `db:"id"`
Name string `db:"name"`
}
err := sqlx.Select(db, &users, "SELECT id, name FROM users LIMIT 10")
连接池深度优化
监控指标
db.Stats().OpenConnections
: 当前打开连接数db.Stats().Idle
: 空闲连接数db.Stats().WaitCount
: 等待连接次数
最佳实践
- 生产环境必须设置连接限制
- 空闲连接数≈平均并发请求数
- 使用
ConnMaxLifetime
防止网络问题导致的陈旧连接 - 监控
WaitDuration
调整连接数
go func() {
for {
stats := db.Stats()
log.Printf(
"Open: %d, InUse: %d, Idle: %d, Wait: %d",
stats.OpenConnections,
stats.InUse,
stats.Idle,
stats.WaitCount,
)
time.Sleep(1 * time.Minute)
}
}()
行业实践参考
云原生部署
- 使用Kubernetes Sidecar模式管理连接
- 实现自动重连机制
- 考虑服务网格连接池管理
微服务架构
- 每个服务实例维护独立连接池
- 通过API网关聚合查询
- 实现Circuit Breaker模式防止级联故障
// 重连示例
var db *sql.DB
func initDB() {
var err error
db, err = sql.Open("mysql", dsn)
if err != nil {
log.Fatal(err)
}
go func() {
for {
if err := db.Ping(); err != nil {
log.Println("Reconnecting...")
db.Close()
db, _ = sql.Open("mysql", dsn)
}
time.Sleep(30 * time.Second)
}
}()
}