Go 里用 SQLite 最省事的写法

后台服务只有一个进程、一台机器、一两个人在用的时候,我第一反应就是上 SQLite:不用装服务端,不用配账号密码,一个文件拷走就是全部数据。Go 里怎么用 SQLite 最省事,结论是选对驱动加打开正确的几个开关,剩下的事交给它自己。

一、先说适用前提

这套写法适合单机部署、写入不密集的场景。我自己那个后台就是这种:定时任务写日志、手动点几下按钮。

不适合的情况也说清楚:多实例同时读写、写入量持续很高、需要跨机器共享同一份数据。这几种情况硬用 SQLite,后面会一直跟锁打交道。

如果只是「数据量以后会变多」的担心,那不构成换数据库的理由。先跑起来,真到瓶颈再换。

二、第一步:驱动别选纯 Go 实现的那类

Go 生态里有不止一种 SQLite 驱动,差别主要在底层用的是哪套实现。

选的时候看两件事:是否需要在开启某些扩展能力时能用得上,以及是否支持你要的并发方式。纯 Go 的实现编译部署最省事,功能上会有限制。

具体动作:把驱动 import 成空白引用注册,然后在连接串里把参数带上,不要用默认参数直接连。

三、第二步:连接串里先定三个参数

连接串看起来是一串零碎选项,其实只关心三件事。

一是忙等超时,遇到别人正在写的时候先等一下,而不是立刻报错。二是日志模式,决定写入时对其他读的影响方式。三是外键约束,默认可能是关的,表关系不会真的生效。

这三个参数决定了你后面会不会莫名其妙遇到锁的问题,建议写代码的第一天就定下来。

四、第三步:把写入收拢到一个地方

SQLite 同时只允许一个写入者。这件事你改不了,能改的是你的代码怎么配合。

做法是让所有写操作走同一个入口,在应用层排队。读可以放开,写排队。

具体动作:找出代码里所有写数据库的地方,把它们收敛到少数几个函数里,不要让业务代码随手就执行一条写语句。

五、Go 里怎么用 SQLite 最省事:连接池和文件位置

Go 的数据库连接池对 SQLite 不一定越多越好。

写并发被限制住的前提下,开太多连接只会让它们互相等。读多写少的场景,可以给读留几个连接。

具体动作:把最大连接数显式设成一个你解释得清的值,而不是用默认值。设完压一遍,看有没有报锁。

文件位置同样重要。放在网络盘或者同步目录里,锁的行为会变得难以预期。

这类问题排查起来很费时间,因为本地怎么测都没事,一上到那台机器就出问题。数据库文件放本地路径,备份用别的方式做。

六、容易卡住的两个点

第一个是测试环境正常、线上偶发报锁。多半是线上并发写法跟测试不一样,或者文件放的位置不同。

第二个是迁移脚本执行到一半失败,留下一个状态不明的库。执行迁移前先复制一份文件,这个习惯成本很低。

常见问题

Q:Go 里用 SQLite 需要装 CGO 吗?

A:看你选的驱动。有的驱动依赖 CGO,交叉编译会麻烦一些;纯 Go 的不需要。选之前先确认你的部署方式能不能接受。

Q:SQLite 写入慢怎么办?

A:先确认是不是每次写入都在单独提交事务。把批量写收进一个事务里,通常是提升最明显的一步。

Q:一个 Go 服务能用几个 SQLite 文件?

A:技术上可以用多个。但文件一多,事务和数据一致性就要你自己保证,小项目建议先用一个。

相关阅读


本文作者西米,37 岁程序员,一个人加五个 AI 员工在跑一家公司。踩过的坑和真实账本都写在公众号「西米分享」。

完整代码、踩坑清单与最新进展,都在公众号。

📱 关注公众号「西米分享」