小工具用 SQLite 存订单。你想趁它还在跑,拷一份数据库留底。目录里一个 app.db,旁边还有 app.db-wal。这时候只带走 app.db,恢复出来的表可能还能查,刚提交的几笔订单却不在里面。
WAL 模式下,新提交的内容可能先留在 -wal,之后才由 checkpoint 写回主库。备份要让 SQLite 自己读出一份一致的数据。
在同一台机器上,用 .backup 拷一份
这里用普通 SQLite 数据库和官方的 sqlite3 命令行,WAL 库只读打开需要 SQLite 3.22.0 或更新版本。到源库所在的机器执行。下面假设当前目录里有 app.db,已经建好可写的 backups 目录,里面还没有 app-copy.db。
sqlite3 -readonly -bail -cmd ".timeout 5000" "app.db" ".backup 'backups/app-copy.db'"
-readonly 用来只读打开源库,.backup 负责写新的备份文件。目录和文件名换成你自己的,目标文件留一个新名字。对仍在用的 WAL 库,确认进程能读取已有的 -wal 和 -shm,或能在源库目录创建这两个文件。源库打不开或遇到锁时,先看权限和并发写入情况。
备份过程中应用可以继续工作。写得特别密时,这次备份可能要等得更久。开始和结束时间都记下来。真要算恢复后还缺哪些订单,再去核对备份里最近一笔已提交的业务记录。备份文件跟源库一样要限制访问。
拿备份查一笔你认识的订单
先对备份文件做结构检查,然后查一条在备份开始前就已提交的记录。下面的 orders 和 42 都是示例,换成你真能核对的表和记录。
sqlite3 -readonly -bail "backups/app-copy.db" "PRAGMA quick_check;"
sqlite3 -readonly -bail "backups/app-copy.db" "SELECT id, status FROM orders WHERE id = 42;"
第一条预期返回 ok。第二条拿状态和业务记录对一遍。光看文件大小,或者只看到表名,没法判断你关心的数据在不在。要做完整的索引和约束检查时,再按库大小和可用时间选择 integrity_check,外键关系用 foreign_key_check 单独看。
用 SQLite 3.53.3 的临时库做了一次验证。关闭自动 checkpoint 后写入 42 号订单,保持写入连接打开,再用在线备份 API 取副本。副本的 quick_check 返回了 ok,也查到了那笔订单。
恢复演练先换个目录
把验过的备份再复制一份到干净目录,让测试实例指向这个副本。用应用打开一张订单、查一次列表,顺手看它有没有自动跑迁移。正式恢复时,先停止写入并关闭连接,把原库目录整体留作回退,再让应用指向单独目录里验证过的库。旧目录里如果还留有 -wal 或 -shm,和原库一起保留。
参考资料
SQLite 正在写入,怎么备份一份能恢复的库
https://java.li/archives/sqlite-backup-wal
评论