SQLite数据库仍然被锁定/无法访问。

4
我有一个关于sqlite3数据库的问题,它在某次访问后仍然被锁定/无法访问。
该行为迄今发生在Ubuntu 10.4和自定义(OpenEmbedded)Linux上。sqlite版本为3.7.7.1)。Db是一个本地文件。
一个C++应用程序定期(5秒钟)访问db。每次执行多个插入语句并包装在延迟事务中。这只在一个线程中发生。与db的连接在整个应用程序的生命周期内保持打开状态。使用的语句也是持久的,并通过sqlite3_reset重复使用。sqlite_threadsafe设置为1(串行化),日志记录设置为WAL。
然后我同时使用sqlite命令行工具打开sqlite db。我输入BEGIN IMMEDIATE;,等待>5s,然后使用END;提交。
此后,应用程序的db访问失败: BEGIN TRANSACTION返回代码1(“SQL错误或缺少数据库”)。如果我在开始之前执行ROLLBACK TRANSACTION,只是为了确保没有已经存在的活动事务,则返回代码5(“数据库文件被锁定”)。
有人有想法如何解决这个问题或者有什么可能导致它的想法吗?
编辑:有一个解决方法:如果出现上述错误,我关闭并重新打开db连接。这解决了问题,但我目前不知道原因。
2个回答

0

Sqlite是一种无服务器数据库。据我所知,它的设计不支持多个来源的并发访问。您正在尝试从应用程序和命令工具同时访问相同的后备文件,因此您尝试执行并发访问。这就是为什么它失败的原因。


它确实支持多个访问,但前提是你的数据库文件存储在支持适当锁定的文件系统上。在网络文件系统上,这非常不可靠(对于任何数据库都是如此;网络和锁定不太兼容)。 - Donal Fellows
@DonalFellows 我改口了。也许你的自定义内核中没有配置所需的文件系统锁定? - gby

0

SQLite连接应该只从一个单线程中使用,因为它们包含用于确保正确并发访问的互斥锁等内容。 (请注意,SQLite始终仅支持单个更新线程,并且在此期间没有并发读取;这是无服务器DB的限制。)

幸运的是,当SQLite连接不执行任何操作时,它们相对便宜,而像缓存准备语句之类的成本实际上相当小;打开尽可能多的连接。

[编辑]: 此外,这将解释关闭和重新打开连接的工作原理:它在新线程中构建连接(并在旧线程中完成所有锁等最终操作)。


问题说明只有两个线程访问数据库:一个在应用程序中,另一个在命令行工具中。因此,每个线程都有自己的连接。 - Hanno S.
@Hanno:从问题中并不完全明显,而表面上的解决方案符合诊断... - Donal Fellows
我还应该指出的是,线程和SQLite连接的限制实际上是它们不能在任何事务已经开始后跨线程共享。(即使没有明确要求,执行SELECT或INSERT也会进行事务处理。) - Donal Fellows

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接