SQLite 的 WAL 模式与并发写
默认模式的问题
SQLite 默认用 rollback journal:写事务进行时,数据库文件被锁,读也得排队。单用户无所谓,几个人同时访问就能感觉到卡。
WAL 改了什么
PRAGMA journal_mode=WAL; 之后,修改先写入 -wal 文件,读操作从"已提交的快照"读,所以:
- 读不阻塞写
- 写不阻塞读
- 同一时刻仍然只有一个写者
最后一条是很多人误解的地方。WAL 解决的是"读写互相排队",不是"支持并行写"。第二个写入者会等待,超时就报 SQLITE_BUSY。
必配的两个参数
PRAGMA journal_mode = WAL;
PRAGMA busy_timeout = 5000;
PRAGMA synchronous = NORMAL;
busy_timeout:拿不到写锁时最多等多久(毫秒),而不是立刻失败。不设这个,稍微并发一下就报错。synchronous = NORMAL:WAL 模式下通常足够安全(断电可能丢最后一个事务,但不会损坏数据库),换来明显的写性能提升。要求零丢失再改回FULL。
什么时候够用,什么时候不够
| 场景 | 判断 |
|---|---|
| 单机、内网几个人用 | 完全够 |
| 读多写少的管理系统 | 很合适 |
| 高频写入(每秒几十次以上) | 谨慎,考虑换 PostgreSQL |
| 多台服务器同时访问同一个库文件 | 不行,文件锁跨网络不可靠 |
备份别直接 cp
WAL 模式下直接复制 .sqlite 文件会漏掉 -wal 里未合并的数据,甚至拷到写一半的状态。正确做法:
sqlite3 app.db ".backup 'backup.db'"
# 或
sqlite3 app.db "VACUUM INTO 'backup.db';"
这两条都在数据库连接层面做一致性快照,可以一边服务一边备份。
本文为个人学习记录,可能存在错误或已过时,仅供参考。
← 返回笔记列表