为了账号安全,请及时绑定邮箱和手机立即绑定

SQLite WAL 模式实战:为什么你还是会遇到 database is locked

标签:
MySQL 数据库

SQLite 明明支持并发,为什么你的程序还是频繁报 database is locked?这篇笔记把 WAL 模式的原理和几个最常见的坑一次讲清。

默认的回滚日志模式问题在哪

SQLite 默认使用回滚日志(rollback journal)。在这种模式下,写事务会对整个数据库文件加排他锁,写入期间所有读操作都被挡在外面。Web 服务这种「大量读 + 少量写」的场景,一个慢写就能让所有请求排队,表现出来就是间歇性的 SQLITE_BUSY

WAL 模式改变了什么

执行一条语句即可切换:

PRAGMA journal_mode=WAL;

WAL(Write-Ahead Logging)把修改先追加写入独立的 -wal 文件,而不是直接改主库文件。带来的直接收益:

  1. 读写不再互斥:读事务看到的是自己开始时刻的快照,写事务往 WAL 追加,两者互不阻塞。
  2. 写入更快:追加写代替随机写,机械盘和云盘上差距尤其明显。
  3. 崩溃恢复更简单:重启后自动从 WAL 回放,不需要人工介入。

注意 WAL 是数据库文件级别的持久设置,切一次就够了,不需要每个连接都执行。

三个最常踩的坑

坑一:写和写仍然互斥。 WAL 只解决读写并发,同一时刻仍然只允许一个写事务。多线程/多进程同时写,第二个写会拿到 SQLITE_BUSY。正确做法是设置 busy_timeout(比如 5000 毫秒),让 SQLite 自己排队重试,而不是在业务层裸重试:

PRAGMA busy_timeout=5000;

坑二:长读事务拖垮 checkpoint。 WAL 文件需要定期把内容合并回主库(checkpoint),但只要有读事务还引用着旧快照,checkpoint 就无法推进,-wal 文件会一直膨胀。排查方向:找出那些「开了事务却忘了提交」的连接,尤其是 ORM 默认开启的隐式事务。

坑三:网络文件系统不支持。 WAL 依赖同主机的共享内存(-shm 文件),把数据库放在 NFS 或容器跨主机挂载卷上会出现未定义行为。这类部署要么退回回滚日志模式,要么换成真正的 C/S 数据库。

什么时候不该用 WAL

如果你的场景是一次性批量导入、只读镜像分发,或者数据库文件需要跨机器拷贝(拷贝时要连 -wal-shm 一起处理,容易漏),回滚日志模式反而更省心。

一句话总结:WAL + busy_timeout 是绝大多数嵌入式场景的正确默认值,剩下的问题基本都出在长事务和部署环境上。

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号

举报

0/150
提交
取消