必须调用 db.ping() 验证连接,且 sqlite 初始化需按顺序执行 pragma journal_mode=wal、foreign_keys=on、encoding=utf-8(建表前),事务必须全程使用 *sql.tx,queryrow 仅用于单行,query 必须显式 rows.close()。

sql.Open 不等于连上数据库,真正验证连接必须调 db.Ping()。别跳过这步,否则第一次查询时才爆错,排查成本翻倍。
为什么必须用 mattn/go-sqlite3 而不是纯 Go 驱动
纯 Go 实现的 SQLite 驱动(比如 glebarez/go-sqlite)无法设置关键 PRAGMA,例如 journal_mode = WAL 或 foreign_keys = ON。高并发写入时会卡死,外键约束形同虚设,中文插入可能乱码。
实操建议:
-
go get github.com/mattn/go-sqlite3是唯一稳定路径,它基于 C SQLite 库,功能完整 - 必须启用 CGO:编译前确保
CGO_ENABLED=1,Alpine 容器需先apk add --no-cache musl-dev sqlite-dev - macOS 上若报头文件缺失,检查
PKG_CONFIG_PATH是否指向 Homebrew 的lib/pkgconfig - Windows 用户推荐 MinGW + gcc ≥ 9.0,MSVC 不兼容
db.Exec("PRAGMA ...") 必须在建表前手动执行
SQLite 默认关闭外键、用 DELETE 日志模式、不校验 UTF-8 编码。Go 驱动不会自动帮你开,每个新连接都要重设。
常见错误现象:
- 外键不生效 → 插入子表数据不报错,但关联查不到
- 多 goroutine 写入频繁阻塞 →
database is locked错误频发 - 中文存成 ??? → Windows 下默认 ANSI 编码
正确做法(按顺序执行):
-
_, _ = db.Exec("PRAGMA journal_mode = WAL")—— 提升并发写性能 -
_, _ = db.Exec("PRAGMA foreign_keys = ON")—— 启用外键约束 -
_, _ = db.Exec("PRAGMA encoding = 'UTF-8'")—— 强制 UTF-8 编码 - 这些语句必须在
CREATE TABLE之前执行,且不能放在事务里
事务中所有操作必须走 *sql.Tx,混用 db.Query 就失效
SQLite 是文件锁模型。db.Begin() 返回的 *sql.Tx 才持有锁;一旦在事务里调用 db.Query 或 db.Exec,该语句就脱离事务上下文。
典型后果:
- 该语句不参与回滚,即使后续
tx.Rollback()也已提交 - 事务隔离性被破坏,读到未提交中间状态
- 锁未释放,其他 goroutine 卡在
database is locked
正确写法:
- 用
tx, err := db.Begin()获取事务对象 - 所有操作都用
tx.Query、tx.Exec、tx.Prepare -
defer tx.Rollback()必须放在tx.Commit()前,且不可忽略错误 - 别在事务里调
db.QueryRow或db.Query,哪怕只是查个计数
QueryRow 和 Query 的边界必须划清
QueryRow 用于至多返回一行的场景(如主键查询、聚合函数);Query 返回 *sql.Rows,必须显式 rows.Close(),否则连接泄漏。
容易踩的坑:
- 对
QueryRow忘记调.Scan()→ 变量保持零值,无报错,静默失败 - 用
Query查单行却没调rows.Next()→Scanpanic 或跳过数据 -
rows.Scan传参不是指针 / 列数或类型不匹配 → 报sql: Scan error on column index 0 - 漏掉
defer rows.Close()→ 连接池耗尽,后续db.Query卡住
示例对比:
err := db.QueryRow("SELECT name FROM users WHERE id = ?", 1).Scan(&name) // ✅ 正确
rows, _ := db.Query("SELECT name FROM users")
defer rows.Close() // ✅ 必须有
for rows.Next() {
rows.Scan(&name) // ✅ 每次循环都要 Scan
}
WAL 模式和外键开关不是“设一次就永久生效”,每次新连接都要重设;事务里的操作一旦脱离 *sql.Tx,就等于没事务。这两点最容易被忽略,也最难 debug。golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











