锁定sqlite3数据库以进行文件下载

7
我在某个系统上有一个sqlite3数据库,需要在持续运行期间下载。停止或暂停访问进程不可取。所以,据我所知,我需要在下载期间持有一个共享锁(如http://www.sqlite.org/lockingv3.html中描述的那样),以避免在下载期间对数据库进行更改和破坏。我应该如何显式地获得这样的锁?下载是由C++程序控制的,因此我需要在那里获取锁。
编辑:thkala建议制作数据库转储。但我更喜欢使用锁定解决方案,因为我不确定是否有足够的内存来完全复制数据库。
3个回答

8

不,不,不,绝对不行!

玩弄锁定并手动复制文件是老旧的做法。SQLite现在有一个适当的备份API可供使用。这是执行SQLite数据库在线拷贝的推荐方法 - 您可以使用它来创建数据库副本,然后在方便的时候下载。

编辑:

如果您绝对需要使用锁定,您可以使用此处概述的方法 - 可能需要将其翻译为C语言:

  • 打开数据库

  • 使用BEGIN IMMEDIATE语句获取共享锁。

  • 手动复制/下载文件-确保您没有漏掉任何文件。至少有DB文件、日志文件和可能的WAL文件。您可能希望将DB放在单独的目录中,以使事情更简单。

  • ROLLBACK您刚刚启动的事务。

我了解这种方法在某些情况下可能很有用,但我必须重申,这不再是推荐的方法。


不知道备份API,非常好! - RushPL
使用备份API存在问题,因为我不确定是否有足够的空间来完整复制数据库。 - Gabriel Schreiber

2

我有点忽视了解决方案: 使用

开始一个事务

BEGIN IMMEDIATE TRANSCTION

并以此结束

END TRANSACTION

获得锁。当调用返回时,如果使用的是IMMEDIATE关键字,则不会使用默认设置,且数据库已经被锁定(已获得保留锁)。


-3

这里的解决方案是错误的,我留下来让后人了解为什么这是一个坏主意。

我认为你也可以通过复制数据库和日志文件(将db和journal都复制到tmp文件中,然后下载它们),然后在远程端尝试打开此数据库,它会自行修复。前提是应用程序使用适当的事务。

请阅读下面的评论,解释为什么这是错误的:

要点是,你可以复制db和journal,但只有在完全相同的时间点获取两者才行。

这几乎是不可能的。


3
不行!不行!不行!这是导致数据损坏的“食谱”!数据库日志要求正确的文件系统语义——当你通过网络复制文件时,你没有这些语义。-1 - thkala
问题1:通过网络,数据库文件可能会在日志之前或之后几秒甚至几分钟被下载。 - thkala
3
问题2:当您下载数据库时,有可能文件的开头处于事务N,而当您完成下载时,它的结尾可能处于事务N+M。请注意,此时您只能获得事务N到N+M之间的数据。 - thkala
我同意这不是一个完全正确的方法来完成这个任务,但我很想看到一个测试是否有效。想象一下,在断电后,一个文件已经同步,而另一个文件没有。必须有一些防止不一致的东西。 - RushPL
@RushPL:秒并非不可能。数据库文件可能会很大,文件访问速度会很慢(CF卡)。此外,在这里赌博似乎不合适。 - Gabriel Schreiber
显示剩余4条评论

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