Django sqlite数据库被锁定

时间:2015-07-21 18:47:57

标签: python django sqlite

我一直在挣扎着" sqlite3.OperationalError数据库被锁定"整天......

搜索似乎是一个众所周知的问题的答案我发现大多数时候sqlite在多线程中不能很好地解释,其中线程可能会超时等待写入db的时间超过5(默认超时),因为另一个线程具有db锁。

因此,有更多的线程与数据库一起使用,其中一个使用事务并经常编写,我开始测量事务完成所需的时间。我发现没有任何事务需要超过300毫秒,因此上述说明并不合理。除非使用事务的线程进行~21(5000 ms / 300 ms)连续事务,而任何其他希望写入的线程都会被忽略

那么其他假设可以解释这种行为呢?

2 个答案:

答案 0 :(得分:7)

我之前遇到过很多关于Sqlite的问题。基本上,没有多个线程可能会写入数据库。如果这是不可接受的,你应该切换到Postgres或其他更好的并发性。

Sqlite有一个非常简单的实现,依赖于文件系统进行锁定。大多数文件系统不是为这种低延迟操作而构建的。对于网络安装的文件系统和某些VPS解决方案使用的虚拟文件系统(最后一个让我获得BTW),尤其如此。

此外,您还拥有Django层,增加了复杂性。你不知道Django什么时候发布连接(虽然我很确定这里有人能详细给出答案:))。但同样,如果您有多个并发编写器,那么<​​strong>需要数据库层而不是并发。周期。

我通过切换到postgres解决了这个问题。 Django让这对你来说非常简单,即使只是很少的停机时间,也可以轻松地迁移数据。

答案 1 :(得分:0)

如果其他人可能通过Google找到这个问题,请点击此处。

SQLite是一个实现&#34; serializable&#34;的数据库引擎。隔离级别(见here)。默认情况下,它使用锁定策略实现此隔离级别(尽管通过启用该链接中描述的WAL模式,似乎可以将其更改为更类似MVCC的策略。)

但即使使用相当粗粒度的锁定,SQLite具有单独的读写锁定,并使用延迟事务(意味着它不会在必要时进行锁定)这一事实意味着仍可能发生死锁。似乎SQLite可以检测到这样的死锁并几乎立即使事务失败。

由于SQLite不支持&#34;选择更新&#34;,提前获取写锁定并因此避免死锁的最佳方法是使用&#34; BEGIN IMMEDIATE&#34;或者&#34;开始独家&#34;而不只是&#34; BEGIN&#34;,但Django目前只使用&#34; BEGIN&#34; (当被告知使用交易时)并且目前没有告诉它使用其他任何东西的机制。因此,结合使用Django,SQLite,事务和并发,锁定失败几乎是不可避免的(除非您手动发出&#34; BEGIN IMMEDIATE&#34;但这非常丑陋且特定于SQLite)。 / p>

但任何熟悉数据库的人都知道,当你使用&#34; serializable&#34;与许多常见数据库系统隔离级别,然后事务通常会因序列化错误而失败。这恰好发生在此死锁所代表的情况中,并且当发生序列化错误时,必须简单地重试失败的事务。事实上,这对我来说很好。

(当然,最后,如果你需要大量的并发性,最后你应该使用更少的&#34; lite&#34;那种数据库引擎。)