6月1日 00:06

SQLite 数据库如何备份和恢复才安全?

SQLite 备份先判断是否在线

SQLite 只有一个数据库文件,看起来复制一下就能备份。但安全备份要先判断数据库是否正在写入。离线数据库直接复制通常没问题;在线数据库如果正在写事务,简单 cp 可能拿到不一致的文件。启用 WAL 模式时还要注意 -wal-shm 文件,漏掉 WAL 可能丢最新数据。

什么时候可以直接复制?

如果应用已经停止,或者能保证没有写入,文件复制最简单:

bash
cp app.db app.backup.db

WAL 模式下更稳的做法是先 checkpoint,再复制主库文件:

bash
sqlite3 app.db "PRAGMA wal_checkpoint(FULL);" cp app.db app.backup.db

取舍是文件复制速度快、恢复简单,但不适合持续写入的在线库。最常见的坑是用 cron 直接复制正在写的数据库,恢复时才发现文件损坏或少了一段数据。

在线备份用什么?

SQLite 命令行的 .backup 使用 backup API,可以在数据库仍可读写时得到一致备份:

bash
sqlite3 app.db ".backup 'app.backup.db'"

恢复时可以在停应用后替换原文件,也可以恢复到新库:

bash
cp app.backup.db app.db sqlite3 restored.db ".restore 'app.backup.db'"

.backup 的优点是不用手动处理 WAL 细节,适合作为常规备份方案。代价是大库备份仍然会占 I/O,最好放在低峰期执行,并把备份文件同步到另一块磁盘或对象存储。

VACUUM INTO.dump 怎么选?

VACUUM INTO 会创建一个压实后的数据库文件,适合归档或清理大量删除后的碎片:

sql
VACUUM INTO 'app.compact.backup.db';

它比普通备份更重,需要额外空间和 I/O,不适合分钟级高频执行。日常备份优先 .backup,低峰维护或归档前再考虑 VACUUM INTO

.dump 会导出 SQL 脚本,适合审查、迁移和救援,但大库恢复会慢:

bash
sqlite3 app.db ".dump" > app.sql sqlite3 restored.db < app.sql

简单记法是:要快恢复用 .backup,要可读迁移用 .dump,要顺便压缩整理用 VACUUM INTO

如何确认备份可用?

备份后至少跑完整性检查:

bash
sqlite3 app.backup.db "PRAGMA integrity_check;"

返回 ok 只是第一步。更可靠的是定期恢复到临时环境,检查核心表行数、最新数据时间和关键业务查询。很多事故不是备份文件不存在,而是权限、路径、属主或恢复脚本有问题。备份方案必须包含恢复演练,否则只能算“复制文件”。

一个保守脚本可以这样写:

bash
set -euo pipefail DB="/data/app.db" OUT="/backup/app_$(date +%Y%m%d_%H%M%S).db" sqlite3 "$DB" ".backup '$OUT'" sqlite3 "$OUT" "PRAGMA integrity_check;"

追问

SQLite 可以直接复制文件备份吗?

可以,但最好在没有写入时做。WAL 模式还要先 checkpoint,避免漏掉 WAL 里的事务。取舍是复制最简单,但在线写入时风险高。踩坑点是只复制主文件,恢复后发现最新数据不见了。

.backupVACUUM INTO 有什么区别?

.backup 关注在线一致性复制,更适合常规备份。VACUUM INTO 会生成压实后的新库,适合归档和碎片整理。取舍是后者更耗 I/O 和空间。边界是线上高峰不要频繁跑 VACUUM INTO

.dump 能当日常灾备吗?

不太建议,它导出可读 SQL,但大库恢复慢。它适合迁移、审计,或者文件损坏时尽量救数据。取舍是可读性换来了恢复时间。踩坑是只保留 .dump,真正故障时恢复窗口超标。

怎么验证备份没有坏?

先跑 PRAGMA integrity_check;,返回 ok 才算基本可用。还应定期恢复到临时库,跑关键业务查询。取舍是验证会增加耗时,但能提前发现问题。边界是文件存在不代表可以恢复。

备份应该保留多少份?

要看数据变更频率和能接受丢多久的数据。常见做法是保留近期高频备份,再保留每周或每月归档。取舍是保留越多越占空间,但回滚选择更多。最大坑是原库和备份都放在同一块磁盘上。

标签:Sqlite