首页 > 解决方案 > 在断电期间,SQLite 将我的数据库回滚到 BEGIN 之前的某个点

问题描述

我的应用程序中有一个 SQLite 数据库。每次应用程序在数据库中修改/添加一行时,应用程序都会通过发出命令来显式启动 SQLite 事务BEING TRANSACTION。在我的数据库中更新/添加数据后,我发出命令COMMIT,或者ROLLBACK如果更新失败。通常的东西(https://www.sqlite.org/lang_transaction.html)。一切正常,直到我断电。

问题是每次我在应用程序执行后断电,启动设备并最终启动应用程序,SQLITE 会保留数据,COMMIT就好像从来没有发生过一样!为什么?BEGINCOMMIT

我还检查了我的应用程序目录中的数据库文件,它具有正确的数据。我还注意到我的应用程序目录中有一个额外的文件<mydatabasefilename>-journal。经检查,这是 SQLite 用于支持回滚不完整事务的临时文件,尤其是在断电期间。

再次,我COMMIT发生在断电之前。我的数据库文件(在我的应用程序目录中检查)包含正确的数据。但为什么<mydatabasefilename>-journal包含较旧的数据?我完全不明白。我在这里错过了什么吗?

标签: androidsqliteandroid-ndk

解决方案


PRAGMA synchronous您的数据库使用什么设置PRAGMA journal_mode?这些可用于控制 sqlite 在这些方面的确切行为。

包含旧内容的文件的行为<mydatabasefilename>-journal听起来像这里描述的回滚日志:https ://www.sqlite.org/lockingv3.html#rollback

当一个进程想要更改一个数据库文件(并且它不是在 WAL 模式下)时,它首先将原始未更改的数据库内容记录在回滚日志中。回滚日志是一个普通的磁盘文件,它始终与数据库文件位于同一目录或文件夹中,与数据库文件同名,加-journal 后缀。[...]

[...]

如果需要回滚以恢复其数据库的完整性,则称回滚日志是热的。当进程处于数据库更新过程中并且程序或操作系统崩溃或电源故障阻止更新完成时,将创建热日志。热门期刊是一种例外情况。热日志的存在是为了从崩溃和电源故障中恢复。如果一切正常(也就是说,如果没有崩溃或电源故障),您将永远不会获得热门期刊。

此处描述了可以设置的不同日志模式:https ://www.sqlite.org/pragma.html#pragma_journal_mode

DELETE 日志模式是正常行为。在 DELETE 模式下,回滚日志在每个事务结束时被删除。实际上,删除操作是导致事务提交的操作。(有关更多详细信息,请参阅标题为SQLite 中的原子提交的文档。)

您可以尝试设置其他设置PRAGMA synchronous,请参阅这些设置:https ://www.sqlite.org/pragma.html#pragma_synchronous

  • 额外 (3)

    EXTRA 同步类似于 FULL,除了包含回滚日志的目录在取消链接以在 DELETE 模式下提交事务后同步。如果提交紧跟在断电之后,EXTRA 会提供额外的持久性。

  • 满 (2)

    当同步为 FULL (2) 时,SQLite 数据库引擎将使用 VFS 的 xSync 方法来确保在继续之前将所有内容安全地写入磁盘表面。这可确保操作系统崩溃或电源故障不会损坏数据库。FULL 同步非常安全,但速度也较慢。FULL 是不处于 WAL 模式时最常用的同步设置。

因此,在您的情况下,设置PRAGMA synchronous = EXTRA;可能会满足您的需求,但这可能会以性能为代价。

您也可以尝试使用https://www.sqlite.org/wal.htmlPRAGMA journal_mode = WAL;中描述的.PRAGMA synchronous


推荐阅读