问题:在SQLite数据库上捕获外部更改

时间:2018-05-30 11:49:30

标签: qt sqlite qfilesystemwatcher

我正在使用我通过QSqlDatabase访问的SQLite数据库来开发一个程序。我想处理(希望很少见)对数据库进行一些更改的情况,这些更改不是程序在运行时引起的(例如,用户可以删除写访问,移动或删除文件或手动修改它)。

我尝试使用QFileSystemWatcher。我让它观察数据库文件,在所有函数中,我阻止了它的信号,这样只有“外部”的变化才能触发改变的信号。

问题是QFileSystemWatcher和/或QSqlDatabase::commit()的实际写入磁盘的检查似乎不会在我调用commit()的那一刻发生,所以实际上,首先QFileSystemWatcher的信号被阻止,然后我更改了一些东西,然后我取消阻止它们然后报告要更改的文件。

每次函数请求更改时,我都会尝试将bool变量(m_writeInProgress)设置为true。然后,“已更改”的插槽会检查是否已请求写入操作,如果是,请再次将m_writeInProgress设置为false并退出。这样,它只会处理“外部”变化。

问题仍然存在,如果在实际写作的确切时刻发生了变化,那么它就不会被捕获。

因此,使用QFileSystemWatcher是实现此目的的错误方法。

怎样才能以安全的方式完成?

感谢您的帮助!

修改

我找到了解决部分问题的方法。在数据库文件上启动独占锁可防止其他连接更改它。这很简单,我只需要执行

PRAGMA locking_mode = EXCLUSIVE
BEGIN EXCLUSIVE
COMMIT

并处理在程序的另一个实例尝试访问数据库时出现的错误。

剩下的就是知道用户(意外地)是否在运行时删除了文件......

1 个答案:

答案 0 :(得分:0)

首先,没有SQLITE支持:SQLITE仅支持监视通过直接控制中的数据库连接创建的更改。无论在与您的流程同时进行的单独流程中发生什么,或者您的流程未运行,设计都完全不受您的控制。

此问题的规范解决方案是使用特定于您的应用程序的密钥(可能还有用户等)加密数据库。然后,没有第三方进程可以使用SQLITE修改数据库。当然,任何进程都可能破坏您的数据库,或者摆脱它 - 这太糟糕了。您可以通过使用加密签名,甚至纠错代码来轻松检测损坏,以便在发生一定程度的损坏时能够恢复数据。您不需要有人移动或删除数据库文件的通知:您将知道何时尝试打开数据库并且“找不到文件”错误会返回给您。

当然,以上所有内容都需要自定义VFS implementation。这对于课程来说非常平等。