科技 · 实用指南
SQLite 提示 database is locked?先找出写入者和事务再调 busy_timeout
把 SQLITE_BUSY 当作锁时间线问题:先确认写入者、连接、事务阶段和日志模式,再决定超时、WAL 或重试。

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 状态;启用后继续监控检查点和写事务时长。
应用最小修复并复验
确定性关闭语句与连接,保证每条退出路径提交或回滚,缩短写事务并串行化不可避免的写入者。
用连接标识和计时重放原失败操作,确认没有重复写入且超出预算会明确失败;持续高并发写入可能需要客户机/服务器数据库。
