8.1 备份三招


8.1 备份三招:backup API、VACUUM INTO 与冷拷贝

本节摘要:单文件形态让 SQLite 的备份看似只是"复制文件",但并发与 WAL 让这句话有了三个前提。本节拆解三种备份方式的机制与适用窗口:backup API 的分页在线复制、VACUUM INTO 的一步到位整理、冷拷贝的前提条件,并对照 mysqldump 与 pg_dump 在各自体系里的定位。

第一招:backup API,在线分页复制

backup API 在两个数据库连接之间逐页拷贝,源库可以在线服务:

sqlite3 *pSrc, *pDst; /* 源与目标各一个连接 */ sqlite3_backup *p = sqlite3_backup_init(pDst, "main", pSrc, "main"); if (p) { int rc; do { rc = sqlite3_backup_step(p, 64); /* 每次拷 64 页,让出控制权 */ if (rc == SQLITE_BUSY || rc == SQLITE_LOCKED) { sqlite3_sleep(100); /* 源太忙:歇口气再试 */ } } while (rc == SQLITE_OK || rc == SQLITE_BUSY || rc == SQLITE_LOCKED); sqlite3_backup_finish(p); /* 释放并返回最终状态 */ }

它的机制决定了两个特性:期间的事务安全——复制过程中若有新事务提交,API 会重启复制以保证目标库是某个时刻的一致快照(这也是"步骤页数别贪多"的原因:每批越小,被写操作打断重启的浪费越少);期间对源库的影响——备份持有读锁,WAL 模式下不挡读写,回滚模式下大备份窗口会拖住写事务。增量备份思想也内建于这套 API:finish 后再 init,新实例只复制变化页。

第二招:VACUUM INTO,一步到位的整理型备份

SQL 层的备份语句,一条命令产出全新的紧凑副本:

VACUUM INTO 'backup-2026-09-06.db';

它在内部运行一次完整 VACUUM:把所有 B-Tree 按序重写进新文件,freelist 清零、页连续、碎片归零。与第一招对比:VACUUM INTO 产出最小最干净的副本(适合归档与传输),代价是源页全读一遍加目标全写一遍,大库耗时更长;backup API 产出与源结构一致的镜像(适合快速热备),代价是带着源库的碎片。两个共同的优点:都是单个一致快照,都可在应用内调用。

第三招冷拷贝看似零成本,前提必须刻在流程里:

冷拷贝的合法性清单: 1. 确认库处于 WAL 模式 → 必须三件套一起拷(主文件 加 -wal 加 -shm),缺 WAL 则尾部事务丢失 2. 更稳的做法:拷之前先 PRAGMA wal_checkpoint(TRUNCATE) 把 WAL 归零,然后只拷主文件 3. 非进程活跃期拷贝;应用进程持有连接时哪怕"没人写"也有隐患 4. 校验:拷完在副本上跑 PRAGMA integrity_check,通过才算备份成功

图:备份三招的机制与选型

图:备份三招的机制与选型

恢复:备份的另一半

备份策略没到"演练过恢复"的程度就不算存在。SQLite 的恢复分三档:整库替换(停应用、换文件、起应用,配合 checkpoint 后的干净副本最简单);单库多副本的择优(同一个库的多份备份中挑 integrity_check 通过的最新者);逻辑级抢救(库损坏但 CLI 还能打开时,.recover 命令尽力导出可读数据到新库——这是损坏场景的最后手段,产出的数据要人工核对)。

⚠️ 最常见的备份事故:定时任务用 cp 拷 WAL 模式的库,只拷了主文件。恢复时发现"最近几小时的数据没了"——不是 SQLite 丢了数据,是备份流程绕过了 WAL。把 checkpoint(TRUNCATE) 写进拷贝脚本的前置步骤,这一类事故即根除。

常见问题速答

**VACUUM INTO 期间能正常写入吗?**能。它内部以只读快照的方式读源库,WAL 模式下不阻塞任何业务操作;只是它本身耗时与库大小成正比,期间会持续占用读 IO。对多 GB 的库,把它安排在低峰期是习惯而非必需。产出文件的尺寸通常明显小于源库——freelist 清零加页连续,压缩比两三成是常态,这也是它适合做"传输用备份"的原因。

**backup API 与 VACUUM INTO 能互相替代吗?**不能,定位互补。热备与定时快照选 backup API(快、可增量、与源同构);归档与传输选 VACUUM INTO(小、干净、单条 SQL)。有团队的做法是组合拳:日常 backup API 快照兜底,每周一次 VACUUM INTO 出归档件——快照保证恢复速度,归档件保证最小体积与长期可读性。

**怎么验证一份备份真的可用?**恢复演练加完整性校验,缺一不可:把备份文件在一个临时连接上打开,跑 PRAGMA integrity_check 得到 ok;再抽查若干业务查询的结果与源库一致。未校验的备份在事故当晚才能发现不可用——那是检验备份策略最昂贵的时刻。校验逻辑应当进定时任务,与备份同一流水线自动完成。

**WAL 模式下三件套分别是必拷的吗?**按场景定。业务在线时的热备不要手拷文件,用 backup API 或 VACUUM INTO 绕开这个问题;停机窗口的冷拷贝,先 TRUNCATE 检查点再只拷主文件最干净;来不及做检查点时,三件一起拷也能得到一致副本,恢复侧会自动重放。唯一不可接受的是"只拷主文件还恰好在活跃写入期"——那不是备份,是赌博。

**增量备份可行吗?**半可行,取决于你接受的定义。backup API 的"再 init 一次只复制变化页"是页级增量,速度快,但产物仍是目标库的完整镜像,不是增量包;要出真正的增量数据包,得在应用层记录上次备份点(rowid 或时间戳)自行导出差异。嵌入式场景的务实答案是降低频率——库本身通常不大,整库快照的成本低到让增量机制失去必要性,这也是它与服务端备份生态最大的心态差异。

本节要点回顾

  • backup API 在线分页复制,WAL 下不挡业务,适合热备;提交重启机制保证快照一致。
  • VACUUM INTO 产出紧凑干净副本,适合归档传输;代价是全量重写耗时。
  • 冷拷贝的前提:checkpoint 归零 WAL 或三件套同拷;拷后必做完整性校验。
  • 备份策略含恢复演练才成立;.recover 是损坏场景的最后手段而非日常工具。

数据保住了,下一节解决"出问题时怎么找到证据"。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U