Flask部署Phusion Passenger后,SQLite加threading.Lock仍锁库
问题根源与解决方案
核心问题:多进程环境下全局锁失效
Phusion Passenger默认采用多进程部署模型,你定义的全局threading.Lock、connection和cursor是进程级变量——每个Passenger启动的进程都会拥有一套独立的副本。这直接导致:
- 不同进程的锁完全独立,无法跨进程同步数据库操作
- 多个进程同时持有数据库连接并操作,触发SQLite的文件级锁冲突,最终出现
database is locked错误
本地Flask开发服务器是单进程多线程模型,全局锁能覆盖所有请求线程,所以不会暴露问题,但部署到多进程环境后锁的同步作用就完全失效了。
次要问题:未及时处理事务
你提到仅执行cursor.execute()不调用.commit(),如果涉及写操作(INSERT/UPDATE/DELETE),未提交的事务会持续持有数据库锁,即便锁在单个进程内生效,长时间挂起的锁也会导致后续请求超时触发锁定错误。
正确处理方式
放弃全局连接/游标,每次操作创建新连接
SQLite连接开销极低,每次数据库操作时创建连接、用完即关是最稳妥的方案,天然适配多进程/多线程环境:def get_db_connection(): conn = sqlite3.connect('db') conn.row_factory = sqlite3.Row # 可选,支持按字段名读取数据 return conn # 数据库操作示例 with get_db_connection() as conn: cursor = conn.cursor() cursor.execute(...) conn.commit() # 写操作必须提交读操作启用只读模式减少锁竞争
纯查询场景可以使用只读连接,避免占用写锁:conn = sqlite3.connect('file:db?mode=ro', uri=True)若要复用连接,改用进程级锁
若担心连接开销需复用连接,必须用进程级锁(如multiprocessing.Lock)替代线程锁,但进程锁需要通过共享文件等跨进程通信方式实现,复杂度远高于每次新建连接,不推荐。临时缓解:延长锁等待超时
可以通过timeout参数延长锁等待时间,减少报错频率,但这只是临时方案,无法解决根本问题:conn = sqlite3.connect('db', timeout=30) # 等待30秒再触发锁定报错
内容的提问来源于stack exchange,提问作者postcoital-solitaire
相关产品推荐
相关产品推荐

