Database / Programming Languages
SQLite WAL:读写并行背后的那本账
理解预写式日志如何改变 SQLite 的提交路径、检查点与故障恢复。
SQLiteSQLiteSQLite Database Engine嵌入应用进程、以单个文件保存主要数据的事务型关系数据库引擎。查看详细解释 → 把数据库引擎嵌入应用进程。默认回滚日志模式会先保存旧页面;而 WALWALWrite-Ahead Logging先把变更可靠记录到日志,再更新主要数据结构的持久化技术。查看详细解释 →(预写式日志)把新的页面版本顺序追加到单独文件中,提交时不必立刻覆盖主数据库。
提交路径发生了什么
事务修改的页面先进入 WAL。提交记录被可靠写入后,事务就可以对新读者可见。旧读者仍从自己开始读取时对应的快照继续工作。
PRAGMA journal_mode = WAL;
PRAGMA synchronous = NORMAL;
PRAGMA wal_checkpoint(PASSIVE);
这使“一个写者、多个读者”在常见负载下更顺畅,但并没有创造多个并行写者。写事务持续太久,其他写者仍会等待。
| 操作 | 主要读取位置 | 是否阻塞普通读者 |
|---|---|---|
| 读取旧快照 | 主库 + WAL 中已提交帧 | 通常不会 |
| 写入事务 | WAL 尾部 | 同时只能有一个写者 |
| 检查点 | WAL → 主数据库 | 受活跃读者边界约束 |
检查点与恢复
检查点把已提交页面复制回主数据库。崩溃后,SQLite 会读取 WAL 中有效的提交边界来恢复一致状态。应用仍然需要正确处理 SQLITE_BUSY、磁盘空间和备份策略。
WAL 是持久化协议的一部分,不是可以随意删除的缓存。复制数据库时,也必须使用 SQLite 的备份 API,或在能保证一致性的条件下同时处理相关文件。