TOC

SQLite WAL 模式

许多人对 SQLite 存在误解,认为“每次写入都会锁定整个数据库”。但实际上,只需一个简单的配置,就能让它轻松应对数千并发用户——这就是Write-Ahead Logging (WAL) 模式。

-- 启用WAL模式
PRAGMA journal_mode=WAL;

-- 设置同步模式为NORMAL(性能与安全性的平衡)
PRAGMA synchronous=NORMAL;

WAL 原理

WAL 是一种日志机制,它将数据修改先写入单独的日志文件,再定期同步到主数据库。这种设计带来了两大核心优势:

  1. 读写并发:读不再阻塞写,写也不再阻塞读
  2. 崩溃恢复:即使系统崩溃,也能从日志中恢复未提交的数据

流程:

  1. 写入流程

    • 数据修改先写入-wal日志文件
    • 主数据库文件保持不变
    • 定期将日志内容批量写入主文件
  2. 读取流程

    • 读者从主数据库文件读取
    • 同时检查WAL日志中的新数据
    • 获得数据的一致性视图
  3. 检查点机制

    • 定期将WAL日志内容合并到主文件
    • 保持日志文件大小可控
    • 可通过PRAGMA wal_checkpoint手动触发

注意事项

注意:不支持分布式部署、不能高频操作的问题依旧还在,WAL 不能解决所有问题。

  1. 网络文件系统:WAL在NFS等网络文件系统上可能有问题
  2. 多进程访问:多个进程可同时读取,但写入仍需协调
  3. 备份策略:备份时需要同时复制.db-wal文件
  4. 内存使用:WAL会占用更多内存缓存日志内容

附录

1. PRAGMA journal_mode

此指令用于设置数据库的日志模式,它决定了事务如何被记录和回滚。其可选值为:

说明
DELETE 默认模式。在事务结束时,回滚日志文件会被删除。这是 SQLite 最传统的日志模式。
TRUNCATE 与 DELETE 类似,但不实际删除文件,而是将日志文件截断为0字节。在某些系统上可能比 DELETE 更快。
PERSIST 不回滚日志文件置零或删除,而是在文件头写入一个无效的魔数,使日志文件不被视为有效。这可以避免删除操作,在部分文件系统上可能提升速度。
MEMORY 将回滚日志存储在内存中而非磁盘上。这能提升事务速度,但一旦程序崩溃或断电,整个数据库可能损坏。仅用于临时数据库
WAL Write-Ahead Logging 模式(即本文作者采用的模式)。修改先写入一个单独的 WAL 文件,支持读写并发。提供了最好的并发性能,是多数现代应用的推荐选择。
OFF 完全禁用回滚日志。事务通过独占数据库锁来实现,无法回滚。性能最高,但安全性最低,不推荐常规使用。

2. PRAGMA synchronous

此指令用于控制 SQLite 在将数据写入磁盘时的“同步”严格程度,即在何时向操作系统确认写入操作已完成。它直接影响数据安全性与写入性能的权衡。其可选值为:

说明
OFF (0) 安全性最低,性能最高。SQLite 将数据交给操作系统后立即继续,不等待实际写入磁盘。如果系统在之后崩溃,数据可能损坏。
NORMAL (1) 性能与安全性的平衡(即本文作者采用的模式)。在大多数关键操作后执行同步,但不像 FULL 那样频繁。在非系统崩溃(如普通程序崩溃)时能保证数据安全,是 WAL 模式下的常用搭配。
FULL (2) 安全性最高,性能较低(是除 WAL 模式外的默认值)。确保所有数据在继续前都已物理写入磁盘。这是最安全的模式,只要磁盘本身未损坏,数据就不会损坏。
EXTRA (3) 比 FULL 更严格,仅在极少需要额外耐久性保证的场景下使用。
如果你有魔法,你可以看到一个评论框~