Pager 生命周期函数:固定页面、运行事务以及在 SQLite 中使其持久化
Source: Dev.to
你好,我是 Maneshwar。我正在开发 FreeDevTools online,目前的目标是构建“一站式开发工具、技巧代码和 TLDR 汇总”——一个免费、开源的中心,开发者可以快速找到并使用工具,无需在互联网上四处搜索。
在上一篇文章中,我们走遍了 pager 的 入口点:打开数据库、获取页面、声明写入意图以及准备日志记录。
今天,我们进入 控制函数,即管理 页面生命周期、事务边界 和 提交 vs 回滚 的函数。这正是 pager 不再仅仅是缓存管理器,而完整展现为 SQLite 事务引擎的地方。
固定页面:sqlite3PagerRef 与 sqlite3PagerUnref
一旦页面交给树模块,分页器必须确保该页面不会在其下方消失。这时引用计数就派上用场了。
sqlite3PagerRef:固定页面
此函数会递增页面的 引用计数 并将页面标记为 已固定(pinned)。
已固定的页面不可触碰:
- 不会被驱逐
- 不会被回收
- 不会被覆盖

只要引用计数非零,分页器就保证该页面的内存保持有效。
sqlite3PagerUnref:释放固定
此函数会递减引用计数。当计数降至零时,页面变为 未固定(unpinned),可以被复用;它可能会被放入缓存空闲链表。
这里会出现一种微妙但关键的行为:当 所有页面 都变为未固定时
- 分页器会释放对数据库文件的 共享锁
- Pager 对象返回到中性、空闲状态

这就是 SQLite 在不需要时避免持有锁的方式,而无需上层显式调用锁操作。
开始写事务:sqlite3PagerBegin
此函数标记 显式写事务 的开始。
它的作用
- 在数据库文件上获取 保留锁
- 打开回滚日志(除非数据库是临时的)
- 将 pager 转换为写模式
如果数据库已经被保留用于写入,则此函数会成为 无操作——这点很重要,因为 sqlite3PagerWrite 可能已经启动了隐式写事务,而 SQLite 永远不会不必要地重复工作。
pager 也可能立即获取 独占锁,而不是等到实际写入开始时才获取。

此选择会影响并发性和延迟,并且完全由 pager 管理。
提交第一阶段:确保数据持久性
SQLite 在 两个不同的阶段 提交。第一阶段由以下函数处理:
sqlite3PagerCommitPhaseOne
这是 持久性阶段。分页器:
- 在数据库头部递增 file‑change‑counter(文件更改计数器)
- 将回滚日志同步到磁盘
- 将缓存中的所有脏页写入数据库文件
- 同步数据库文件本身
在此阶段之后,数据库文件已包含新数据,而日志仍然存在,因此仍可进行恢复。此时事务是 崩溃安全 的,但尚未最终完成。

提交第二阶段:宣告胜利
第二阶段完成提交:
sqlite3PagerCommitPhaseTwo
此函数最终确定日志文件——删除、截断或使其失效。一旦完成:
- 不再需要恢复
- 事务正式完成
- 锁可以安全降级
此分阶段设计使 SQLite 能在提交序列的任何点上抵御崩溃。

回滚:无错误撤销
当出现错误或应用程序请求时,pager 会走另一条路径。
sqlite3PagerRollback
此函数:
- 从回滚日志中恢复原始页面内容
- 还原所有内存中的页面
- 完成日志的收尾工作
- 将独占锁降级为共享锁
两个重要保证
- 回滚不会失败
- 数据库保持一致状态
无论执行期间情况多么混乱,回滚总会成功。这是 SQLite 最强的正确性承诺之一。
保存点:嵌套安全网
SQLite 并不把事务视为平面结构。每条 SQL 语句都在一个保存点内部运行,应用程序也可以自行定义保存点。分页器为此提供了两个函数。
sqlite3PagerOpenSavepoint
此函数:
- 创建一个新的保存点处理器
- 记录当前回滚日志的位置
- 捕获当时的数据库状态
保存点会 堆叠——多个保存点可以共存。

sqlite3PagerSavepoint – 释放或回滚
同一个函数根据请求执行 两种截然不同的操作。
保存点释放
- 销毁保存点处理器
- 保留自保存点以来的所有更改
保存点回滚
- 将数据库状态恢复到保存点时的状态
- 撤销其后所做的所有更改
- 删除已回滚的保存点以及所有更新的保存点
该机制使 SQLite 能够回滚单条语句,而无需中止整个事务,也无需重新打开文件或重置锁。仍然全部由分页器处理。

更大的全局
如果现在放大视角,模式应该一目了然。分页器:
- 拥有页面的生命周期
- 拥有事务边界
- 拥有日志记录
- 拥有持久性
- 拥有恢复
- 拥有回滚
更高层只 请求 操作。它们从不强制正确性;而是依赖分页器来实现。
包装分页器章节
在过去的几篇文章中,我们已经从以下内容转变:
- 日志
- 事务
- 锁
- 保存点
- 将所有内容粘合在一起的分页器函数
我关于 SQLite 的实验和实操示例位于此处:
lovestaco/sqlite – sqlite‑examples
参考文献
- SQLite Database System: Design and Implementation – Sibsankar Haldar.
- FreeDevTools – 免费开发者工具集合。

👉 查看:
欢迎任何反馈或贡献!
它是在线的、开源的,随时可供任何人使用。
⭐ 在 GitHub 上给它加星: