ERP推单队列用SQLite落盘,备份时只复制一个.db文件,恢复后却少了最近的任务,应该先检查数据库是否采用WAL模式。
本文依据项目实际数据库初始化代码,用新建实验文件库验证主文件复制与SQLite在线备份的差异。没有读取生产库、启停项目服务或请求金蝶;演示单号仅用于观察本地数据。
1. 当前数据库启用了WAL
项目打开数据库后执行:
javascript
db.pragma('journal_mode = WAL');
在WAL模式下,事务提交后,变更可以先保存在写前日志中,尚未全部回写到主数据库文件。当前连接已经能查询到数据,并不意味着只复制主文件就一定带上这些变更。
同一数据库中保存着推单队列、推送记录、接口日志和基础资料。备份缺少最近变更,影响的可能不只是页面上的一条日志,还可能包括待推任务或防重关联。
这里讨论的是本地SQLite的一致性备份,不是金蝶账套备份,也不能用于推断目标系统有没有收到过某张单。
2. 怎样稳定构造"已提交,但主文件副本没有"
本地实验先使用项目真实初始化函数创建表,手动完成一次checkpoint,让初始表结构落到主文件;随后仅对这份实验库关闭自动checkpoint。
接着用实际队列函数新增一条演示任务。原连接能读到1条queued任务,同时实验库仍保持打开。此时分别执行主文件复制和SQLite在线备份,结果如下:
| 读取对象 | push_jobs记录数 |
|---|---|
| 原连接 | 1 |
| 仅复制主.db文件得到的副本 | 0 |
| 使用db.backup生成的副本 | 1 |
本例特意控制了checkpoint时机,使这个差异可以复现。它不表示所有运行中的主文件副本都会恰好少1条;复制时机、checkpoint和写入活动不同,结果也会不同。

图1:新建实验库中的构造任务。不是生产数据丢失事件或真实ERP输出。
3. 为什么不能用"文件存在"判断备份完整
本例中的主文件副本能够打开,表也存在,但它不包含刚提交的演示任务。因此,只检查文件大小非零或文件能打开,不能替代数据范围核对。
直接把主文件和旁边的日志文件分几次复制,也不能自动保证它们来自同一个一致时间点。数据库仍在写入时,先后复制可能得到不匹配的文件组合。
checkpoint负责将WAL中的内容回写到主文件,它本身不是备份。即使某次checkpoint完成,如果之后继续写入,复制窗口的问题仍然存在。不能把"执行过一次checkpoint"当作今后任意文件复制都安全的承诺。
4. 本地验证用的是SQLite在线备份接口
本次通过当前项目依赖提供的备份方法生成单独副本:
javascript
await db.backup(backupPath);
之后用独立只读连接打开该副本,并核对队列表中的构造任务。本次实际验证了这条备份路径能包含上述已提交数据;没有验证生产并发压力、备份耗时或异常中断恢复。
真实运行时还要处理目标路径、空间不足、备份错误和完成记录。只有备份方法成功完成,才进入副本检查;不能在异步操作尚未完成时就把文件标为可恢复。
这份SQLite快照也不会自动包含连接配置、外部运行日志或目标ERP的数据。完整恢复方案需要列清各类材料的范围及保护方式,不能把一个数据库文件称为整套系统备份。
5. 验收要包含恢复后的业务核对
建议在隔离目录打开备份,检查数据库完整性、表结构、迁移版本和关键记录。再按连接与单据标识抽查任务、推送记录以及必要的来源进度。
恢复出一个旧快照后,本地记录可能落后于目标系统:备份之后写入ERP的单据,不会因为本地恢复就自动消失。不能只根据恢复后的queued或pending状态,把所有任务重新保存一遍。
实际恢复前应设计目标只读核对和防重措施,尤其关注请求发出后尚未确认结果的任务。备份文件可读与对接业务可安全继续,需要分别验收。
本次结论限定为:在受控的WAL窗口中,仅复制主文件漏掉了演示任务,SQLite在线备份副本包含了该任务。没有执行生产恢复或证明任何真实单据已经丢失。