我有一个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
在某些运行中,我甚至都不会遇到这个块,但是当我这样做时,它永远不会出现它(继续重试,但我不断从exc_info获取'数据库被锁定'错误。如果我理解读者/ writer锁定使用正确,一些等待应该有助于争用。这听起来像死锁,但我不在我的代码中使用任何事务,并且每个SELECT或INSERT只是一次性。但是,有些线程,在进行操作时保持相同的连接(包括SELECTS和INSERTS以及其他修饰符的混合)。
如果您可以对此进行遮挡,并且还要修复它(除了使用不同的数据库引擎之外),我会对它进行处理。
答案 0 :(得分:0)
每次尝试写入数据库时,Sqlite都会锁定整个数据库。你的一个主题是否有可能不断写作?是只有一个线程命中数据库锁还是全部购买其中一个?
答案 1 :(得分:0)
这是一个不那么优雅的临时修复:在写入周围使用外部独占锁,而不是依赖于内部sqlite锁定。问题中的上述块基本上都包含一个系统范围的锁,每个线程必须在写入之前获取。因为sqlite3在编写时会锁定整个数据库,所以我希望这不会增加更多的开销。
另一方面,读取可以在不获取锁定的情况下继续进行,我认为 可能 可以使用限制较少的读取器锁定sqlite3。
答案 2 :(得分:0)
我也在这个网站上遇到了这个问题,这个网站每天有大约200个用户(可能会有1000个页面浏览量)。重试只是没有帮助(我最终将他们的数量增加到100,其间有短暂的睡眠)。我不记得它是哪个版本的SQLite,但我从中吸取了教训,如果你想对SQLite数据库进行可靠的并发写入,那么最好使用其他数据库,如MySQL或PostgreSQL。
即使您使用OperationalError-s解决了您的问题,这也很有用,因为最终对SQLite文件的并发写入将会很好地扼杀性能。