• kk

    一个日活几百的小站,SQLite 频繁报 database is locked,第一反应是并发太高撑不住。实际查下来三条都跟并发量无关。

    1. 长事务没提交。有个导出功能在一个事务里遍历几万行再写文件,期间任何写操作都拿不到锁。解法是把读和写拆开,事务里只做数据库操作。
    2. 连接没设 busy_timeout。默认是 0,一撞锁立刻报错,不等待。加上 PRAGMA busy_timeout=5000 之后,绝大部分瞬时冲突会自己消化掉。
    3. 用了 DELETE 日志模式。改 WAL 之后读写不再互斥:PRAGMA journal_mode=WAL。注意 WAL 需要文件所在目录可写,容器里挂载成只读就会退回原模式。

    还有一个隐蔽的:备份脚本用 cp 直接拷 .sqlite 文件,拷的瞬间恰好有写事务,拿到的是半个库。要么用 sqlite3 的 .backup 命令,要么在 WAL 模式下连同 -wal、-shm 一起拷。

    结论:SQLite 的锁问题九成是用法问题。真到写并发撑不住的时候,报的通常是 SQLITE_BUSY 而不是这种模糊的 locked,那时候再考虑换库。

    主楼
  • xiaoman

    新人想问一下,busy_timeout 是每个连接都要设一次吗?还是设一次就全局生效。

    #1
  • kk

    第 2 条是关键。busy_timeout 设了之后基本看不到 locked 了,剩下就是长事务。

    #2

发表回复

登录后回复