sqlite3 '数据库被锁定'无论重试都无法解决

4 投票
3 回答
5468 浏览
提问于 2025-04-15 17:56

我有一个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 个回答

0

我也遇到过这个问题,那个网站每天大约有200个用户(也就是大概1000次页面浏览)。尝试重试并没有什么帮助(我最后把重试次数增加到100次,中间还加了短暂的等待)。我不记得那是哪个版本的SQLite,但我明白了一个道理:如果你想要在SQLite数据库上进行可靠的同时写入,最好还是换用其他数据库,比如MySQL或PostgreSQL。

即使你解决了操作错误的问题,最终对SQLite文件的同时写入也会严重影响性能。

0

这里有一个不是特别优雅的临时解决办法:在写入数据时使用一个外部的独占锁,而不是依赖sqlite内部的锁。问题中的代码块基本上是用一个系统范围的锁包裹起来的,每个线程在写入之前都必须先获取这个锁。因为sqlite3在写入时本身就会锁住整个数据库,所以我希望这不会增加太多额外的负担。

另一方面,读取操作可以在不获取锁的情况下进行,我觉得这可能和sqlite3需要的较不严格的读取锁是可以兼容的。

0

Sqlite在你每次尝试写入数据库的时候,会把整个数据库锁住。你有没有可能有一个线程一直在写数据?是只有一个线程在碰数据库的锁,还是大部分线程都在碰?

撰写回答