为啥 Core Data SQLite 存储不能从 OS X 10.8 向后兼容到 10.4?

Posted

技术标签:

【中文标题】为啥 Core Data SQLite 存储不能从 OS X 10.8 向后兼容到 10.4?【英文标题】:Why are Core Data SQLite stores not backwards compatible from OS X 10.8 to 10.4?为什么 Core Data SQLite 存储不能从 OS X 10.8 向后兼容到 10.4? 【发布时间】:2012-08-08 19:45:52 【问题描述】:

如果我的应用在 Mountain Lion (SQLite 3.7.12) 上创建了一个新的 Core Data 存储,则同一应用在尝试在 Tiger (SQLite 3.1.3) 上打开文件时会收到 NSPersistentStoreInvalidTypeError 错误。在 Tiger Mac 上运行sqlite3 命令行工具在打开数据库时不会产生任何错误,但是“.dump”命令显示 SQLite 认为它是空的。

但是,如果数据库是在 Tiger 上创建的,则它可以在 Mountain Lion 上进行编辑,然后在 Tiger 上再次编辑,没有任何问题。

Mountain Lion 中是否发生了一些变化,使得新创建的持久性存储不再应该向后兼容?或者是否有我可以启用的设置以便它们启用?据我所知,我没有使用任何较新的 SQLite 功能,例如 3.1.3 中没有的预写日志记录。此外,这不是在 Lion 上创建的数据库的问题。

更新:SQLite change history 表明版本 3.7.10 中存在文件格式更改。你应该可以设置PRAGMA legacy_file_format=ON:

当这个标志打开时,新的 SQLite 数据库会在一个文件中创建 所有版本的 SQLite 都可以读写的格式 回到 3.0.0。

这适用于我直接使用sqlite3。但是,当我通过 NSSQLitePragmasOption 选项将其设置为 NSPersistentStoreCoordinator 时,它似乎被忽略了:Tiger 上的 sqlite3 再次将数据库视为空。

【问题讨论】:

【参考方案1】:

首先,术语问题。根据Wikipedia 的说法,我相信你在这里谈论的问题是forward compatibility:“前向兼容性旨在让设计能够优雅地接受为其后续版本设计的输入。”在这种情况下,随 OS X 10.4 发布的 sqlite3 (3.1.3) 版本是否能够处理 OS X 10.8 中更新版本的 sqlite3 (3.7.12) 创建的磁盘数据格式?

根据sqlite3 documentation,sqlite3 不承诺磁盘格式将完全向前兼容,仅在限制范围内向后兼容,即新版本可以读取旧版本生成的数据库。使用sqlite shell 的一个简单的数据库创建示例很容易证明,虽然 10.4 版本创建的数据库可以被 10.8 版本读取,但反之则不然。碰巧我有一台 10.4 机器 (ppc),它恰好有最新版本的 sqlite3 以及 Apple 提供的系统版本:

$ /macports/bin/sqlite3 -version
3.7.13 2012-06-11 02:05:22 f5b5a13f7394dc143aa136f1d4faba6839eaa6dc
$ /macports/bin/sqlite3 test.db <<EOF
>      BEGIN TRANSACTION;
>      CREATE TABLE t1 (t1key INTEGER
>                   PRIMARY KEY,data TEXT,num double,timeEnter DATE);
>      INSERT INTO "t1" VALUES(1, 'This is sample data', 3, NULL);
>      INSERT INTO "t1" VALUES(2, 'More sample data', 6, NULL);
>      INSERT INTO "t1" VALUES(3, 'And a little more', 9, NULL);
>      COMMIT;
> EOF
$ /macports/bin/sqlite3 test.db  "select * from t1 limit 2";
1|This is sample data|3.0|
2|More sample data|6.0|
$ /usr/bin/sqlite3 test.db  "select * from t1 limit 2";
SQL error: unsupported file format
$ /usr/bin/sqlite3 -version
3.1.3

如果数据库是在 10.8 上创建然后移动到 10.4,也会发生同样的事情。当使用 10.7 版本的 sqlite3 (3.7.7) 运行相同的测试时,10.4 版本 能够读取数据库文件。我认为这些格式一直保持向前兼容是一件幸运的事情。看来现在运气已经用完了。除非 Apple 在某处保证 CoreData SQL 数据库在这些 OS X 版本范围内向前兼容,否则您可能需要在应用程序中处理这种兼容性,例如,通过跨平台转储和重新创建数据库版本。

【讨论】:

感谢您的回答。我认为您对术语的理解是正确的。据我所知,Apple 没有做出任何保证,但它通常的工作方式是 Apple 明确告诉你什么时候会发生故障。如果 NSPropertyListSerialization 或 NSKeyedArchiver 突然改变格式,就会出现混乱。我已经用关于 SQLite 格式兼容性的信息更新了这个问题,我相信他们会承诺。

以上是关于为啥 Core Data SQLite 存储不能从 OS X 10.8 向后兼容到 10.4?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Core Data 一对多关系从 JSON 数组填充 sqlite 数据库

Core Data:为啥要创建自定义持久存储?

在 Iphone 中使用 Core Data 从 SQLite 数据库中获取主键值

Core Data SQLite 存储在更新后变为只读

在 NSLibraryDirectory 或 NSApplicationSupportDirectory 中存储 Core Data Sqlite?

由于继承缺陷,Core Data sqlite 存储单表?