
使用 database/sql 配合 mattn/go-sqlite3 时,SQLite 的并发安全依赖于连接隔离与正确配置;无需手动加锁,但必须为每个 goroutine 提供独立连接,并启用 cache=shared 等关键参数以支持多连接协作。
使用 `database/sql` 配合 `mattn/go-sqlite3` 时,sqlite 的并发安全依赖于连接隔离与正确配置;无需手动加锁,但必须为每个 goroutine 提供独立连接,并启用 `cache=shared` 等关键参数以支持多连接协作。
SQLite 本身是进程内数据库,其并发模型与传统服务端数据库(如 PostgreSQL)有本质区别:它不通过网络服务协调访问,而是依赖文件系统锁和内部页缓存策略来管理读写冲突。在 Go 中使用 github.com/mattn/go-sqlite3 驱动时,驱动本身不自动序列化跨 goroutine 的操作,但只要遵循正确的连接使用模式,即可安全实现高并发读写。
✅ 正确做法:每个 goroutine 应使用独立的 *sql.Conn 或从 *sql.DB 获取专属连接(而非共享单个 *sql.DB 句柄后直接复用),并确保连接字符串启用共享缓存:
// 推荐:启用 shared cache 和读写创建模式
db, err := sql.Open("sqlite3", "file:app.db?cache=shared&_journal=wal&mode=rwc")
if err != nil {
log.Fatal(err)
}
// 设置连接池参数(可选但推荐)
db.SetMaxOpenConns(20) // 控制最大并发连接数
db.SetMaxIdleConns(5) // 保持空闲连接数,减少频繁创建开销
⚠️ 关键参数说明:
- cache=shared:允许多个连接共享同一内存页缓存,是支持并发写入的前提(否则默认 private 模式下写操作会相互阻塞);
- _journal=wal:启用 WAL(Write-Ahead Logging)模式,大幅提升并发读性能(读不阻塞写,写不阻塞读);
- mode=rwc:确保数据库以读写方式打开(rwc = read-write-create)。
❌ 错误模式示例(应避免):
// ❌ 危险:多个 goroutine 直接调用 db.Query/Exec 而不获取专属连接
// 这会导致连接复用竞争,可能触发 SQLITE_BUSY 或死锁
go func() {
_, _ = db.Exec("INSERT INTO logs VALUES (?)", time.Now())
}()
// ✅ 正确:显式获取连接,用完释放
go func() {
conn, err := db.Conn(context.Background())
if err != nil { panic(err) }
defer conn.Close()
_, _ = conn.ExecContext(context.Background(), "INSERT INTO logs VALUES (?)", time.Now())
}()
此外,SQLite 在遇到锁冲突时默认不会无限重试——例如写操作遭遇 SQLITE_BUSY,驱动将立即返回错误(除非显式配置 busy_timeout)。如需自动重试,可添加超时参数:
// 自动等待最多 5 秒再报错
db, _ := sql.Open("sqlite3", "file:app.db?cache=shared&_journal=wal&mode=rwc&_busy_timeout=5000")
? 总结:
- 不需要 sync.Mutex 或 channel 手动串行化数据库操作;
- 核心原则是「连接隔离 + 共享缓存 + WAL 日志」;
- 合理设置连接池与 busy timeout,可兼顾性能与健壮性;
- 始终通过 context 控制操作超时,避免 goroutine 永久阻塞。










