Watch at Ease看见世界,读懂生活。

科技 · 实用指南

SQLite 提示 database is locked?先找出写入者和事务再调 busy_timeout

把 SQLITE_BUSY 当作锁时间线问题:先确认写入者、连接、事务阶段和日志模式,再决定超时、WAL 或重试。

原创示意图:一个 SQLite 写入者持锁,另一个连接在有界计时器旁等待。
原创示意:先找出写入者和锁区间,再提高超时。 Watch at Ease

SQLite 的“database is locked”只说明所需锁不可用,并不会告诉你哪个进程、连接或事务造成冲突。先提高 busy_timeout,可能只是把长事务藏起来。

建立连接时间线,区分可等待的短暂争用与 DEFERRED 读转写升级,再用带上限的重试验证最小修复。

先冻结失败现场

保存完整异常、数字错误码、SQL 操作、进程、线程、连接标识和时间;同时记录失败发生在 BEGIN、首次写入、COMMIT、检查点、恢复还是关闭阶段。

不要删除 -wal 或 -shm 文件,也不要只复制主数据库;列出所有可能打开该路径的应用、终端、迁移、后台任务和编辑器。

建立逐连接事务时间线

记录每个连接的打开、BEGIN、首次读取、首次写入、提交或回滚、语句结束和连接关闭,并附上 journal_mode、timeout 和事务模式。

如果写事务内包含网络、文件或人工等待,把这些慢操作移出事务,再考虑重试参数。

区分等待与事务升级失败

SQLite 可同时有多个读事务,但只能有一个写事务。DEFERRED 事务先读后写时需要升级;另一个写入者存在时,首次写入可能直接返回 SQLITE_BUSY。

只有在工作单元确定会写且应在开始时取得写入槽时才用 BEGIN IMMEDIATE;它仍可能因已有写入者而失败。

只把 busy_timeout 用于短暂争用

超时只规定等待多久,不会替你提交别的连接、关闭泄漏游标或缩短事务。每个连接都应测量等待时长、重试次数和锁持有者。

仅重试幂等操作或副作用受控的完整事务;加入抖动和硬上限,并在最终失败时保留原时间线。

把 WAL 当并发模式,不是万能解锁

WAL 通常允许读者与写入者并行,但仍只有一个写入者;独占模式、清理或恢复期间仍可能出现 SQLITE_BUSY。

启用前确认所有进程和文件系统兼容,并安全处理数据库与 WAL 状态;启用后继续监控检查点和写事务时长。

应用最小修复并复验

确定性关闭语句与连接,保证每条退出路径提交或回滚,缩短写事务并串行化不可避免的写入者。

用连接标识和计时重放原失败操作,确认没有重复写入且超出预算会明确失败;持续高并发写入可能需要客户机/服务器数据库。

原创概念插画:读事务面对单写入者门槛,并分出 WAL 与有限等待路径。
原创概念插画:分类锁路径后再选择 IMMEDIATE、WAL 或有限等待。 Watch at Ease