Go 中操作 SQL 数据库完全指南
Go database/sql 标准用法:驱动注册、连接池配置、查询与 Scan、预编译语句、事务、常见访问模式与工具选型(sqlc/sqlx/GORM)。本文从连接到生产模式全覆盖。
本文依据官方文档整理,未执行运行验证或性能基准。代码片段展示局部用法,业务函数、数据和环境需按项目补齐;版本与配置以所引文档为准。
直接回答:Go 操作 SQL 数据库的标准入口是 database/sql 包——驱动注册后 sql.Open 拿连接池(不是单连接),QueryContext+Scan 读数据,ExecContext 写数据,Prepare 预编译高频语句,Tx 管事务。生产要点:连接池参数必须调、查询必须带 Context、行必须关闭。
连接:Open 得到的是池
import (
"database/sql"
_ "github.com/lib/pq" // 驱动注册
)
db, err := sql.Open("postgres", dsn)
if err != nil { return err }
defer db.Close() // 在应用生命周期结束时关闭,不要每个请求建池
db.SetMaxOpenConns(25) // 最大打开连接
db.SetMaxIdleConns(5) // 空闲连接
db.SetConnMaxLifetime(5 * time.Minute) // 连接寿命
if err := db.PingContext(ctx); err != nil { return err }
sql.Open 返回可复用的数据库句柄,可能仅验证参数而不建连;用 PingContext 验证连通性。连接池参数不调等于裸奔:默认无上限的连接数能拖垮数据库。
查询与修改
// 单行
var name string
err := db.QueryRowContext(ctx, "SELECT name FROM users WHERE id=$1", id).Scan(&name)
if errors.Is(err, sql.ErrNoRows) { return err } // 交由上层映射业务“未找到”
if err != nil { return err }
// 多行——rows 必须 Close
rows, err := db.QueryContext(ctx, "SELECT id, name FROM users")
if err != nil { return err }
defer rows.Close()
for rows.Next() {
var id int; var name string
if err := rows.Scan(&id, &name); err != nil { return err }
}
if err := rows.Err(); err != nil { return err }
// 写
res, err := db.ExecContext(ctx, "UPDATE users SET name=$1 WHERE id=$2", name, id)
if err != nil { return err }
_ = res
事务
tx, err := db.BeginTx(ctx, nil)
if err != nil { return err }
defer tx.Rollback()
if _, err := tx.ExecContext(ctx, "UPDATE users SET name=$1 WHERE id=$2", name, id); err != nil {
return err
}
return tx.Commit()
defer tx.Rollback() 是安全网——Commit 成功后 Rollback 返回 sql.ErrTxDone,不会撤销已提交事务。Commit 报错不能当作成功;部分网络故障下还需业务层核对提交结果。
工具选型
| 工具 | 定位 |
|---|---|
| database/sql 裸用 | 可控性最高,样板多 |
| sqlx | 小幅增强(StructScan 等),保留 SQL |
| sqlc | SQL 生成类型安全 Go 代码,编译期校验 |
| GORM | 全功能 ORM,开发快,黑盒多 |
团队 SQL 能力强选 sqlc/sqlx,追求 CRUD 速度选 GORM——sqlx 和常见 GORM 驱动依赖 database/sql;sqlc 也可生成 pgx 原生代码,并非都经 database/sql。资源和事务管理原则仍适用。
常见问题(FAQ)
Q:QueryRow 的 ErrNoRows 算错误吗?
A:是"业务上的没找到"——Scan 返回它时单独判断,别和系统错误混为一谈,更别当 500 返回。
Q:连接池满了的表现是什么?
A:请求阻塞等连接(默认无限等待)——表象是接口集体变慢。监控 MaxOpenConns 水位与等待时间,及早发现。
Q:为什么强调 Context 版本的方法?
A:Query/Exec 不接收调用方的 Context,但数据库或驱动自身的超时仍可能生效。生产代码一律用 QueryContext/ExecContext,把上层超时传进数据库层。
官方参考
资料核对日期:2026-09-29。