脱机数据同步

注意

此产品已停用。 有关使用 .NET 8 或更高版本的项目的替换,请参阅 Community Toolkit Datasync 库

脱机数据同步是 Azure 移动应用的 SDK 功能。 数据存储在本地存储中。 当你的应用处于脱机状态时,你仍然可以创建、修改和搜索数据。 当设备处于联机状态时,数据会与 Azure 移动应用服务同步。 当客户端和服务上更改同一记录时,SDK 支持冲突解决。

脱机同步具有以下优势:

  • 提高应用响应能力
  • 在网络连接不佳时提高应用可靠性
  • 限制高延迟或按流量计费的网络使用
  • 支持断开连接的使用

以下教程演示如何使用 Azure 移动应用将脱机同步添加到移动客户端:

什么是同步表?

Azure 移动应用 SDK 提供 IRemoteTable<T>,用于直接访问服务。 如果设备没有网络连接,操作将失败。 同步表(由 IOfflineTable<T>提供)针对本地存储提供相同的操作。 然后,本地存储可以稍后与服务同步。 在执行任何操作之前,必须初始化本地存储。

什么是本地存储?

本地存储是客户端设备上的数据持久性层。 大多数平台将 SQLite 用于本地存储,但 iOS 使用核心数据。 还可以实现自己的本地存储。 例如,将 SQLite 版本与 SQLCipher 配合使用来生成加密存储。

脱机同步的工作原理是什么?

客户端代码控制本地更改何时与数据同步服务。 在 推送 本地更改之前,不会向服务发送任何内容。 同样,仅当 拉取 数据时,本地存储才会填充新的或更新的数据。

可以推送所有表、表列表或一个表的挂起操作:

// All tables
await client.PushTablesAsync();

// A list of tables
var tablesToPush = new string[] { "table1", "table2" };
await client.PushTablesAsync(tablesToPush);

// A single table
await table.PushItemsAsync();

同步

推送操作会将操作队列中的所有挂起更改发送到服务。 挂起的更改通过 HTTP REST 调用发送到服务,后者反过来会修改数据库。

推送操作在执行任何拉取操作之前完成。 拉取操作从服务拉取已更改的数据,并将其存储在本地存储中。

隐式推送

如果针对具有挂起的本地更新的表执行拉取,则拉取将首先执行该表的推送。 此推送有助于最大程度地减少已排队的更改与服务器中的新数据之间的冲突。 可以选择通过在 PullOptions中设置 PushOtherTables 来配置所有表的推送:

var pullOptions = new PullOptions { PushOtherTables = true };
await table.PullItemsAsync(pullOptions);

拉取记录子集

可以选择指定用于确定哪些记录应包含在脱机数据库中的查询。 例如:

var query = table.CreateQuery().Where(x => x.Color == "Blue");
await table.PullItemsAsync(query);

增量同步

Azure 移动应用实现增量同步。仅提取自上次拉取操作以来已更改的记录。 增量同步可节省处理大型表的时间和带宽。

对于每个唯一查询,最后一个成功传输记录的 UpdatedAt 字段作为令牌存储在脱机存储中。 最后一个 UpdatedAt 值存储在增量令牌存储中。 增量令牌存储作为脱机存储中的表实现。

性能和一致性

同步有时会过早停止。 例如:

  • 用于同步的网络在同步过程中变得不可用。
  • 在同步期间强制关闭应用程序。

为了最大程度地降低脱机数据库中一致性问题的风险,每个记录都会在收到时写入数据库。 可以选择性地决定分批将记录写入数据库。 批处理操作可提高拉取操作期间脱机数据库写入的性能。 但是,它们还会增加表元数据与表内数据不一致的风险。

可以按如下所示优化写入之间的间隔:

var pullOptions = new PullOptions { WriteDeltaTokenInterval = 25 };
await table.PullItemsAsync(pullOptions);

此代码收集成批 25 条记录的写入。 性能测试表明,性能最多可提高 25。 大于 25 的 WriteDeltaTokenInterval 值不会显著提高性能。

净化

可以使用 IOfflineTable<T>.PurgeItemsAsync清除本地存储的内容。 如果客户端数据库中存在过时的数据,或者想要放弃所有挂起的更改,则可能需要清除。 清除会清除本地存储中的表。 清除表:

await table.PurgeItemsAsync("", new PurgeOptions());

如果表中存在挂起的更改,PurgeItemsAsync() 方法将引发 InvalidOperationException 错误。 在这种情况下,可以强制清除:

await table.PurgeItemsAsync("", new PurgeOptions { DiscardPendingOperations = true });

清除是清理脱机存储中的表的最后手段,因为它会擦除缓存中的所有记录,并要求重新下载这些记录。