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

Flask使用peewee操作SQLite在生产环境出现database is locked报错如何处理

问题成因

  • SQLite本身是文件型数据库,采用全局文件级排他锁处理写操作,同一时间仅允许一个连接执行写入操作,并发场景下多个写请求争抢锁时就会触发database is locked报错。
  • 你的代码存在明显的不合理设计:before_request钩子中每次请求都会执行db.create_tables操作,哪怕参数safe=True不会重复建表,也会触发SQLite的系统表查询甚至写操作,相当于每次请求都额外增加了一次锁争抢逻辑,大幅提升了锁冲突概率。
  • 连接管理逻辑存在漏洞:你使用after_request钩子关闭连接,该钩子仅在请求无异常抛出时才会执行,一旦请求处理过程中出现异常,数据库连接不会被正常关闭,持有的锁也无法释放,进一步加剧锁占用问题。
  • 若生产环境使用多线程WSGI服务器,未配置合理的数据库连接池、锁超时时间过短,也会放大锁冲突的概率。

解决方法

1. 调整建表逻辑

将create_tables操作从请求钩子中移除,仅在应用启动时执行一次:

# 应用初始化阶段执行,仅执行一次
if __name__ == '__main__':
    db.connect()
    db.create_tables([Post, User], safe=True)
    db.close()
    app.run()
# 生产环境用WSGI服务器启动的话,放在应用实例化后的初始化逻辑里即可

2. 修复连接管理逻辑

将释放连接的逻辑改为使用teardown_request钩子,该钩子无论请求是否抛出异常都会执行,避免连接泄漏:

@app.before_request
def before_request():
    db.connect()

@app.teardown_request
def teardown_request(exc):
    if not db.is_closed():
        db.close()

3. 优化数据库配置

替换默认的SQLite数据库实例为peewee提供的SqliteQueueDatabase,自带连接队列管理,适配多线程并发场景,同时设置合理的锁超时时间、开启WAL模式提升并发性能:

from peewee import SqliteQueueDatabase

db = SqliteQueueDatabase(
    'your_database.db',
    timeout=30,  # 锁等待超时时间,单位秒,可根据业务调整
    pragmas={
        'journal_mode': 'wal',  # 开启WAL模式,支持并发读+单写,大幅提升并发性能
        'cache_size': -1024 * 64,  # 设置页缓存大小
    }
)

4. 业务层优化

  • 尽量缩短写事务的执行时长,不要在事务中执行HTTP请求、文件读写等耗时操作,减少锁的持有时间。
  • 高频读场景可增加缓存层,减少直接访问数据库的请求量。

5. 长期演进方案

如果业务并发量持续上涨,建议替换为MySQL、PostgreSQL等支持行级锁的关系型数据库,SQLite本身的设计定位就是低并发、轻量的使用场景,不适合高并发写入的生产服务。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 09:09:00