Watch at Ease看见世界,读懂生活。

科技 · 实用指南

SQLite 备份完成就够了吗?轮换前重新打开并验证快照

备份调用完成只证明复制过程结束,不代表候选文件符合恢复约定。重新只读打开准确文件,执行 SQLite 与应用检查,安全提升后再轮换旧的可靠快照。

原创技术示意图,展示创建、只读重开、SQLite 检查、应用检查、提升和延后轮换。
原创技术示意图:准确候选文件通过结构、外键和应用检查前,仍然只是候选。 Watch at Ease

SQLite 备份调用成功只是恢复验收的起点。先写入唯一候选路径,正确关闭目标,再只读打开这个准确文件,避免检查误落到在线数据库。

验收既需要引擎级证据,也需要应用级证据。仅在所有检查都通过后才在目标文件系统上提升候选,并保留上一份可靠备份,直到提升后的文件再次打开成功。

1. 创建候选,而不是最终轮换目标

源数据库继续使用或需要进度与分页时,使用 SQLite 在线备份 API;Python 通过 Connection.backup() 提供它。VACUUM INTO 也能生成一致的在线紧凑快照,但输出必须是新文件或空文件,中断时仍可能留下不完整或损坏的文件。

把候选写入将要提升的目录。活动 WAL 数据库不应默认只复制主 .db 文件;若流程必须复制文件,就要主动静止数据库或处理全部必需的伴随文件。

2. 只读重新打开准确候选

关闭目标连接后,以只读 URI 打开候选本身。不要在源连接上运行验收查询,也不要使用可能指向在线库的路径别名。提升前记录路径、大小、哈希、SQLite 与 Python 版本、创建方法和结果。

在 CPython 3.12.14、SQLite 3.53.1 的 Linux 实验中,Connection.backup() 候选可只读打开;提升后又单独重开目标路径。这个边界能发现内存成功标志看不到的路径错误。

3. 组合结构、外键与应用检查

要求 PRAGMA quick_check 只返回一行 ok,或者在时间允许时运行更完整的 integrity_check。两者都不验证外键;SQLite 明确说明 integrity_check 不发现外键错误,因此还要单独运行 foreign_key_check 并要求空结果。

随后验证应用真正需要的恢复约定:user_version 或迁移表、必需表和索引、已知哨兵记录、关键计数或不变量及代表性读取。四行实验得到 quick_check=ok、无外键行和 sentinel=(sentinel, 3);破坏前16字节的副本在重开时被拒绝。

4. 先提升,最后轮换旧副本

任何检查失败都要让候选留在轮换集之外,保留上一份可靠备份,并记录准确失败查询。不要原地修复候选后宣称通过;重新创建快照才能保持来源清楚。结构检查通过也不证明业务数据完整、最新或语义正确。

全部通过后,用同一文件系统的重命名或替换进行提升。Python 说明 os.replace 成功时具有原子性,但跨文件系统可能失败。删除或老化旧备份前,再打开提升后的路径并重复最小哨兵检查,同时定期在隔离环境验证完整恢复流程。

原创技术示意图,对比在线备份 API、VACUUM INTO 和受控文件复制并汇入共同验收门。
原创技术示意图:创建方法不同,但完成的候选都必须经过同一套重开与验证。 Watch at Ease