用 Go 语言操作 SQLite 的一些注意事项
最近把博客的数据库从 MySQL 迁移到了 SQLite,主要迁移原因有:
- 使博客系统更加轻量,一键部署
- 方便备份,一个普通文件(不能直接拷贝文件)
- 方便部署,MySQL有点重,我不需要那么复杂
- SQLite 官方说其能支撑中小型网站数据库,我信了
代码改动其实很少,但是迁移过程遇到不少的坑,这篇文章简单记一下一些注意事项。
注:公司最近一位同事也恰好也用到了这个 SQLite 数据库,我发现他也有隐藏 BUG,只是因为没有压测,没有发现。
本文环境:
- 编程语言:Go + CGO
- SQLite3:mattn/go-sqlite3
共享缓存模式
设置 cache
为 shared
模式:官方文档。
据官方文档说这样会大大减少并发连接时内存的占用。
1 2 3 4 5 6 7 8 9 |
|
最大连接数
1
|
|
SQLite3 支持多线程模式,但似乎那个模式只是为了在多个线程之间共享同一个连接,并不是为了支持并发。
如果不开启这个选项,可能会报错:database table is locked.
最大一个连接?会不会影响性能?会。但是为了数据安全不得已这样做。
实测我博客的 QPS 能达到几千,所以还是决定用它替换了 MySQL。
不区分大小写
SQLite3 的 text 类型默认 COLLATE 是 BINARY,即区分大小写。
如果要不区分大小写,应该在字段后面加上 COLLATE NOCASE
。
1 2 3 4 5 |
|
记得关闭查询结果
1 2 3 |
|
否则可能导致死锁。
获得原始 sqlite3.SQLiteConn
我要获取原始 sqlite3.SQLiteConn
的原因是为了备份。
官方的例子说不能直接拿到原始连接(忘记在哪里说的了)。
我是用以下方式来获取原始连接的,还算比较好使(官方的不太优雅):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
值得注意的是:Raw()
回调中的 dc
只能在回调中被使用,不能在回调函数退出后继续使用。
数据库备份
虽然 SQLite3 就一个数据文件,但是不能直接复制文件的方式来达到备份的目的。因为有其它连接可能正在更新文件。
以下代码片段来自我博客实现,可以参考一下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
|