You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

单线程用锁仍遇peewee.OperationalError:数据库锁定,概率约万分之一

问题分析与解决建议

核心问题排查

你用了threading.Lock做线程同步,但仍出现SQLite锁定崩溃,大概率和以下几点有关:

  • Peewee默认的SQLite连接是单线程模式,多线程共享同一连接时,即便加了线程锁,也可能因连接内部状态冲突触发锁问题。
  • 线程锁仅包裹了update执行逻辑,但如果ActivityTracker模型在其他地方还有操作,或者连接本身的事务状态未妥善处理,会加剧锁竞争。
  • SQLite写操作会锁定整个数据库,高频率调用下,哪怕有线程锁,也可能因锁等待超时触发崩溃。

具体修复方案

  1. 配置线程安全的SQLite连接
    初始化SqliteDatabase时,添加threadlocals=True参数,确保每个线程拥有独立的数据库连接,从根源避免多线程连接冲突:

    db = SqliteDatabase(Settings.stats_conf_database_location, threadlocals=True)
    
  2. 将update操作包裹在显式事务中
    显式声明事务可以避免隐式事务带来的锁状态异常,配合线程锁进一步降低冲突概率:

    @staticmethod
    def update_daily_activity(time):
        with ActivityTracker_locker:
            with db.atomic():
                ActivityTracker.update(
                    {ActivityTracker.activity_time_curr: ActivityTracker.activity_time_curr + int(time)}
                ).where(ActivityTracker.date == _datetime.date.today()).execute()
    
  3. 确保全局锁的唯一性与覆盖范围
    确认ActivityTracker_locker是全局唯一实例,且所有操作ActivityTracker表的代码都使用该锁,避免其他操作绕过锁引发冲突。

  4. 备选方案:改用查询后更新(低并发场景适用)
    如果高并发不是核心需求,可先查询记录再更新,虽然效率稍低,但锁冲突概率更低:

    @staticmethod
    def update_daily_activity(time):
        with ActivityTracker_locker:
            with db.atomic():
                tracker = ActivityTracker.get(ActivityTracker.date == _datetime.date.today())
                tracker.activity_time_curr += int(time)
                tracker.save()
    

额外注意事项

  • 排查其他操作数据库的代码,确认是否存在未同步的写操作,哪怕频率低,也可能和这段高频率代码产生锁竞争。
  • SQLite本身不适合高并发写场景,若后续调用频率持续升高,建议切换到PostgreSQL、MySQL等支持高并发的数据库。

内容的提问来源于stack exchange,提问作者Si si

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 18:53:29