(十二)备份数据库并在新路径恢复
1. 从连接备份已经提交的数据
启用 WAL 后,打开中的数据库旁可能有 -wal、-shm 文件。已提交更新可能仍在 WAL 中,直接复制主文件会漏掉这些变化。使用 SQLite 连接提供的 backup(),让 SQLite 生成一致的数据库副本。Python 3.12 的备份接口 也可对照第五章的连接管理阅读。
# 项目文件:catalog_project/src/cataloghub/backup.py
from contextlib import closing
import os
from pathlib import Path
import sqlite3
from .storage import open_db
def backup(source, destination):
destination = Path(destination).resolve()
if destination == Path(source).resolve() or destination.exists():
raise ValueError("请选择一份尚不存在的备份文件")
destination.parent.mkdir(parents=True, exist_ok=True)
temporary = destination.with_suffix(destination.suffix + ".tmp")
# SQLite 自己读取一致状态,包含仍在 WAL 中的已提交数据。
with (
closing(open_db(source, readonly=True)) as origin,
closing(sqlite3.connect(temporary)) as target,
):
origin.backup(target)
if target.execute("PRAGMA integrity_check").fetchone()[0] != "ok":
raise ValueError("备份完整性检查失败")
target.commit()
os.replace(temporary, destination)
return str(destination)先写到新的临时数据库,执行 integrity_check,得到 ok 再替换为正式备份文件。目标已存在时,命令提示另选文件名,便于保留不同时间的备份。
2. 恢复后重新查询
# 在 catalog_project 中生成一次备份。
uv run catalog backup instance/backups/books-20261020.sqlite3
# 指定新的数据库文件恢复,再查询同一份状态。
uv run catalog --database instance/restored.sqlite3 restore instance/backups/books-20261020.sqlite3
uv run catalog --database instance/restored.sqlite3 query
备份数据库包含书目、批次报告与拒收记录;原始字段快照仍在 instance/archives/,保存交付数据时也要复制这个目录。恢复练习先核对总数和最近修改的书名,再把 CATALOG_DB 指向恢复文件、重开查询服务,完成一次页面筛选。