简介
Go语言标准库 database/sql,提供统一的数据库操作接口,支持连接池管理、事务控制、预处理语句等核心功能。开发者通过该库的通用接口(如sql.Open、db.Query,db.Exec)操作不同数据库,无需关心底层差异。
各数据库驱动实现
- MySQL:github.com/go-sql-driver/mysql
- PostgreSQL:github.com/lib/pq
- SQLite:github.com/mattn/go-sqlite3
- SQL Server:github.com/denisenkom/go-mssqldb
- Oracle: github.com/godror/godror
数据库连接和设置
- 默认启用连接池,避免频繁创建/销毁连接。
- 合理设置 MaxOpenConns避免数据库过载,MaxIdleConns减少连接重建开销。
- 监控指标:通过数据库的 SHOW PROCESSLIST或驱动提供的统计接口观察连接使用情况。
import (
    "database/sql"
    _ "github.com/go-sql-driver/mysql"
)
// 连接数据库
db, err := sql.Open("mysql", "user:password@tcp(localhost:3306)/dbname")
// 这个很少用。是关闭整个连接池。
defer db.Close()连接池设置:
db.SetMaxOpenConns(100)  // 最大活跃连接数
db.SetMaxIdleConns(10)   // 最大空闲连接数
db.SetConnMaxLifetime(time.Hour) // 连接最大存活时间Ping 机制:通过 db.Ping() 验证数据库连通性。
if err := db.Ping(); err != nil {
    log.Fatal("数据库连接失败:", err)
}查询数据
- db.Query():执行 SELECT 查询,返回 *sql.Rows。
- db.QueryRow():执行单行查询,返回 *sql.Row。
注:必须关闭 Rows 和 Stmt。忘记 rows.Close() 或 stmt.Close() 可能会导致连接池耗尽。
rows, _ := db.Query("SELECT id, name FROM users")
defer rows.Close() // 必须关闭释放资源
for rows.Next() {
    var id int
    var name string
    rows.Scan(&id, &name) // 按列顺序扫描到变量
}
if err = rows.Err(); err != nil { // 检查遍历错误
    // 处理错误
}新增和更新数据
- db.Exec():执行 INSERT/UPDATE/DELETE 等非查询操作。
事务
封装事务接口(BeginTx、Commit、Rollback),通过 db.Begin() 或 db.BeginTx() 开启事务。
隔离级别:通过 db.BeginTx(ctx, &sql.TxOptions{Isolation: sql.LevelSerializable}) 设置。
tx, _ := db.Begin()
_, err1 := tx.Exec("UPDATE account SET balance = balance - 100 WHERE id = 1")
_, err2 := tx.Exec("UPDATE account SET balance = balance + 100 WHERE id = 2")
if err1 != nil || err2 != nil {
    tx.Rollback() // 回滚
} else {
    tx.Commit()   // 提交
}预处理语句
预处理语句,统一使用 ? 占位符。如下所示:
db.Query("SELECT * FROM users WHERE id = ? AND age > ?", 123, 18)PostgreSQL 驱动(如 lib/pq 或 pgx)会自动将 ? 转换为 $1, $2, $3 ...
使用预处理语句有如下优势:
- 防 SQL注入:通过占位符(? 或 $1)绑定参数,自动转义输入。
- 性能提升:数据库预编译 SQL,重复执行时效率更高。
stmt, _ := db.Prepare("INSERT INTO users(name) VALUES(?)")
defer stmt.Close()
names := []string{"Alice", "Bob"}
for _, name := range names {
    stmt.Exec(name)
} 沙滩星空的博客
沙滩星空的博客