sqlite3.OperationalError: database is locked 是SQLite文件级写锁导致的并发冲突,非数据库损坏;根本原因是多个连接/线程同时写入时,未及时提交事务或连接未关闭,使锁长期持有;可通过connect(timeout=5)设置抢锁等待时间,但须配合正确事务管理与连接隔离。

sqlite3.OperationalError: database is locked 是什么情况
这不是数据库损坏,而是多个连接(或同一连接的多个线程)同时尝试写入时,SQLite 的默认锁机制触发了阻塞——它用的是文件级锁,写操作会锁住整个数据库文件。一旦某个写事务没及时提交、被阻塞、或在长循环里没释放连接,其他写请求就会立刻报这个错。
怎么设置 timeout 参数让写操作等一会儿再报错
关键就在 connect() 的 timeout 参数:它控制“等待数据库解锁”的最大秒数,不是连接超时,也不是查询超时。默认是 0.0(即不等待,冲突立即报错),设成 5 或 10 就能让写操作多等几秒。
-
sqlite3.connect("db.sqlite", timeout=5)—— 推荐从 5 开始试,别盲目设太大 - 如果用了
con.execute("BEGIN IMMEDIATE"),timeout同样生效,但只作用于 BEGIN 阶段的锁获取 - 注意:这个 timeout 不影响已开始的写操作执行时间,只管“抢锁”那一下
为什么只加 timeout 还可能继续报错
timeout 只解决“等锁”问题,但锁不释放的根本原因还在代码里。常见坑包括:
安全 Python 代码沙箱:在隔离的沙箱中执行任意 Python 代码,预装 requests、NumPy、pandas 库。返回 stdout、stderr。
- 忘记调用
con.commit()或con.rollback(),导致事务一直挂着 - 在 with 语句外手动管理连接,但异常路径下没 close,连接池或线程里残留未关闭的
Connection - 用
threading.Thread并发写,却把同一个Connection对象传给多个线程——SQLite 连接不是线程安全的 - 使用了
PRAGMA journal_mode = WAL却没配好检查点(checkpoint),WAL 文件堆积也会间接引发锁争用
更稳的并发写法建议
单机轻量场景下,比死等 timeout 更可靠的是控制写入节奏和隔离粒度:
立即学习“Python免费学习笔记(深入)”;
- 所有写操作尽量包在
with sqlite3.connect(..., timeout=10) as con:里,确保自动 commit/close - 避免长事务:不要在一个事务里循环 insert 几千条,拆成每 100 条一次
commit() - 读多写少?考虑开启 WAL 模式:
con.execute("PRAGMA journal_mode = WAL"),它允许多个读 + 一个写并发,但要注意定期PRAGMA wal_checkpoint - 真有高并发写需求,SQLite 就不是合适选型了——换 PostgreSQL 或加一层队列(如 Redis + worker)做串行化
timeout 是止痛药,不是手术刀。锁住的本质,永远是事务没及时收口,或者一个连接被多线程误共享。

















