sqlite3 '数据库被锁定'无论重试都无法解决
我有一个sqlite3数据库,几个线程(大约3到4个)在使用它。我知道sqlite3在多个线程同时访问时的一些限制,具体可以参考这个链接:http://www.sqlite.org/faq.html#q6,但我觉得这不是问题所在。
这些线程既要读取数据,也要写入数据。每当我进行写入时,我会使用以下的结构:
try:
Cursor.execute(q, params)
Connection.commit()
except sqlite3.IntegrityError:
Notify
except sqlite3.OperationalError:
print sys.exc_info()
print("DATABASE LOCKED; sleeping for 3 seconds and trying again")
time.sleep(3)
Retry
在某些情况下,我甚至没有进入这个代码块,但一旦进入,就一直卡在这里(不断重试,但我总是收到“数据库被锁定”的错误信息)。如果我理解得没错,读写锁的使用应该能帮助解决争用问题。听起来像是死锁,但我在代码中并没有使用任何事务,每次的SELECT或INSERT都是一次性的。不过,有些线程在操作时会保持同一个连接(这些操作包括SELECT、INSERT和其他修改)。
如果你能帮我分析一下这个问题,并提供一些解决方案(除了换数据库引擎之外),我会非常感激。
3 个回答
我也遇到过这个问题,那个网站每天大约有200个用户(也就是大概1000次页面浏览)。尝试重试并没有什么帮助(我最后把重试次数增加到100次,中间还加了短暂的等待)。我不记得那是哪个版本的SQLite,但我明白了一个道理:如果你想要在SQLite数据库上进行可靠的同时写入,最好还是换用其他数据库,比如MySQL或PostgreSQL。
即使你解决了操作错误的问题,最终对SQLite文件的同时写入也会严重影响性能。
这里有一个不是特别优雅的临时解决办法:在写入数据时使用一个外部的独占锁,而不是依赖sqlite内部的锁。问题中的代码块基本上是用一个系统范围的锁包裹起来的,每个线程在写入之前都必须先获取这个锁。因为sqlite3在写入时本身就会锁住整个数据库,所以我希望这不会增加太多额外的负担。
另一方面,读取操作可以在不获取锁的情况下进行,我觉得这可能和sqlite3需要的较不严格的读取锁是可以兼容的。
Sqlite在你每次尝试写入数据库的时候,会把整个数据库锁住。你有没有可能有一个线程一直在写数据?是只有一个线程在碰数据库的锁,还是大部分线程都在碰?