SQLite多线程读写遇‘database is locked’问题及选型咨询
问题分析与解答
一、「database is locked」错误的原因
结合你的代码和SQLite的锁机制,问题大概率出在这两点:
- 写入端未及时释放锁:如果有其他进程/线程正在往
test表写入tick数据,且写入操作没及时提交事务、或者事务执行时间过长,SQLite会持有全局独占写锁,后续查询请求因无法获取共享读锁,等待超时后就会触发锁错误。 - 连接/游标管理不规范:你的代码没展示数据库连接创建逻辑,如果是全局共享一个连接/游标,且没设置合理的超时时间(
sqlite3默认超时5秒),锁等待超过阈值就会报错。另外,如果在多线程环境下复用同一个连接(sqlite3默认不支持多线程共享连接),也会直接引发锁冲突。
你的查询逻辑本身没问题,但连接资源如果没及时释放,也可能间接加剧锁冲突。
二、SQLite是否适合这类同时读写的tick数据场景?
结论:不适合高频读写的tick数据场景,原因如下:
- SQLite是文件型数据库,写操作会触发全局独占锁:只要有一个写入事务在执行,所有其他读写操作都会被阻塞。如果tick数据是高频写入(比如每秒几十上百条),会导致查询请求频繁被阻塞,甚至出现锁超时错误。
- 并发性能有限:SQLite的设计定位是轻量、单进程/低并发场景,无法像MySQL、PostgreSQL这类客户端-服务器型数据库那样支持高并发读写分离、多连接并行处理。
如果你的tick数据写入频率极低(比如每秒几条),且查询压力不大,可以临时用SQLite,但需要做优化:
- 延长连接超时时间:比如
conn = sqlite3.connect('your_db.db', timeout=30),给锁等待留足时间 - 写入端用短事务:每次写入后立即提交,不要长时间持有事务
- 避免多线程共享同一个数据库连接,每个线程单独创建连接
优化后的查询代码示例
补全规范的连接管理逻辑,避免潜在的锁问题:
import sqlite3 import time def get_ltp(): # 每次查询创建独立连接(高并发场景可改用连接池) conn = sqlite3.connect('your_db.db', timeout=10) c = conn.cursor() try: query = """select * from test order by rowid desc LIMIT 1""" results = c.execute(query).fetchall() for i in results: print(i) finally: # 确保关闭连接释放资源 conn.close() for i in range(20): get_ltp() time.sleep(1)
内容的提问来源于stack exchange,提问作者Naga
相关产品推荐
相关产品推荐

