生产环境开启 WAL 模式是解决 SQLite 读多写少场景下锁竞争的有效手段,但前提是文件系统支持且应用能接受额外的临时文件。
先说结论:WAL 模式通过追加日志而非覆盖原文件来减少写锁持有时间,适合并发读取频繁的场景。
- 适合读并发远高于写并发的业务
- 先准备确认文件系统权限及类型
- 验收检查 -wal 和 -shm 文件是否正常生成
命令速用版
在 SQLite 命令行或代码中执行以下 pragma 指令即可开启:
PRAGMA journal_mode=WAL;执行后返回 wal 即表示成功,后续连接通常会自动沿用该模式。
为什么会这样
默认的 DELETE 模式下,SQLite 写入时需要锁定整个数据库文件,此时其他读写请求都会被阻塞。开启 WAL(Write-Ahead Logging)后,写入操作先将变更记录追加到单独的日志文件中,读者可以继续读取旧版本的主文件,写者同时写入日志,从而大幅减少锁等待。
这种机制改变了事务提交的持久化方式,写入者不再直接修改主数据库文件,而是等待检查点(checkpoint)进程将日志合并回主文件。
分步处理
1. 备份数据:在生产环境修改任何数据库配置前,务必先冷备份数据库文件。
2. 执行开启命令:确保当前只有一个连接访问数据库,执行 PRAGMA journal_mode=WAL;。如果有多个连接,所有连接都需要感知到模式变更,建议重启应用服务。
3. 检查文件变化:开启成功后,数据库目录除了原有的 .db 文件外,会新增 -wal 和 -shm 后缀的文件。
4. 配置检查点:默认情况下 SQLite 会自动检查点,但高写入负载下可能需要手动或被动触发。可通过 PRAGMA wal_autocheckpoint=1000; 调整阈值。
怎么验证是否生效
1. 查询模式:执行 PRAGMA journal_mode;,返回结果应为 wal。
2. <观察文件>:在数据库文件所在目录,确认是否存在正在增长的 -wal 文件。如果有写入操作,该文件大小会动态变化。
3. 并发测试:在应用层模拟多个读请求和一个写请求同时执行,观察读请求是否不再因写锁而超时。
常见坑
1. 网络文件系统不支持:WAL 模式依赖特定的文件锁机制,在 NFS 或部分网络共享存储上可能无法正常工作或导致数据损坏,本地磁盘最稳妥。
2. 旧版本兼容:极老旧的 SQLite 客户端可能不支持 WAL 模式文件,确保所有访问该数据库的工具版本一致。
3. 日志文件残留:如果数据库非正常关闭,-wal 文件可能不会自动合并。再次打开时 SQLite 会尝试恢复,但部署脚本中最好清理残留锁文件。
4. 只读文件系统:WAL 模式需要写入临时文件,如果数据库所在目录权限设置为只读,开启后会报错。
参考来源
- SQLite 官方文档 - WAL Mode: https://www.sqlite.org/wal.html
- SQLite 官方文档 - PRAGMA journal_mode: https://www.sqlite.org/pragma.html#pragma_journal_mode