Python 后台任务频繁 database is locked:SQLite WAL 模式排查实录

举报
shijiu_dev 发表于 2026/10/29 09:48:50 2026/10/29
【摘要】 从后台任务偶发的 database is locked 入手,分析 SQLite 默认日志模式、长事务和超时设置的影响,并给出 Python sqlite3 的连接、事务与并发改造示例。

问题不是“数据库坏了”

最近维护一个 Python 采集服务时,日志里偶尔出现 sqlite3.OperationalError: database is locked。任务运行在 4 个线程里,日常写入量很小,所以第一反应是 SQLite 不适合并发。但复现后发现问题并不是“数据库坏了”,而是默认配置、事务边界和重试策略一起放大了锁等待。

服务原来的写法是:每个任务先查询远程接口,拿到结果后再写数据库;一次批次包含数百条记录,全部放在同一个事务里。接口偶尔变慢时,写事务就会持续十几秒。另一个线程此时尝试写入,只能立刻报错,因为连接没有设置合理的等待时间。

三个容易忽略的点

1. WAL 模式需要配合连接参数

PRAGMA journal_mode=WAL 能让读写并发更顺畅,但它是数据库级设置;而 busy_timeout 是连接级设置。只切换 WAL 并不能解决所有锁冲突。每个新连接都应该设置超时、同步模式和需要的约束。

import sqlite3

DB_PATH = "tasks.db"

def connect():
    conn = sqlite3.connect(
        DB_PATH,
        timeout=5,
        isolation_level=None,
        check_same_thread=True,
    )
    conn.execute("PRAGMA journal_mode=WAL")
    conn.execute("PRAGMA synchronous=NORMAL")
    conn.execute("PRAGMA busy_timeout=5000")
    conn.execute("PRAGMA foreign_keys=ON")
    return conn

这里把 isolation_level 设为 None,后续由业务代码明确控制事务。这样不会因为忘记提交,让连接长期占用写锁。

2. 不要在事务里做网络请求

把“请求远程接口”和“写数据库”拆开,是最有效的改造。先把网络结果放入内存队列,再开启短事务批量写入。写事务只包含 SQL,不包含 sleep、HTTP 调用和文件上传。

def save_batch(conn, rows):
    with conn:
        conn.execute("BEGIN IMMEDIATE")
        conn.executemany(
            "INSERT INTO task_result(batch_id, payload) VALUES (?, ?)",
            rows,
        )

BEGIN IMMEDIATE 会在事务开始时尝试取得写预留锁。多个写入者因此排队,而不是先做一堆计算,最后提交时才发现锁被占用。配合 busy_timeout,短时间的竞争会等待,而不是马上失败。

3. 不要盲目增加线程数

SQLite 适合单机、低运维成本的工作负载,但同一时刻仍只有一个写入者。把线程从 4 个提高到 32 个,只会让更多请求争抢同一把锁。更稳妥的做法是“并行采集、单队列顺序写入”:采集线程可以并发,数据库写入由一个专用 worker 消费队列。

WAL 的适用边界

WAL 适合本地磁盘上的读多写少场景,不适合把数据库文件放到 NFS、SMB 等网络共享目录。备份时也不要只复制主文件,建议使用 SQLite 的在线备份 API,或者确保主文件、-wal、-shm 状态一致。长时间高频写入后,可以观察 WAL 文件大小,在低峰期执行一次 checkpoint。

改造后,我加了两个指标:写入事务耗时,以及 database is locked 的出现次数。压测时仍会出现排队,但请求不再直接失败;单条事务耗时也稳定在几十毫秒内。对这类小服务来说,正确的连接参数、短事务和明确的生产者消费者边界,往往比直接更换数据库更划算。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。