Azure 移动应用中的脱机数据同步

什么是脱机数据同步?

脱机数据同步是 Azure 移动应用的客户端和服务器 SDK 功能,开发人员可以轻松地创建无需网络连接即可正常运行的应用。

当应用处于脱机模式时,仍可以创建和修改保存到本地存储的数据。 当应用重新联机时,它可以将本地更改与 Azure 移动应用后端同步。 此功能还支持在客户端和后端上更改同一记录时检测冲突。 然后,可以在服务器或客户端上处理冲突。

脱机同步具有以下优势:

  • 通过在设备上本地缓存服务器数据来提高应用响应能力
  • 创建在出现网络问题时仍然有用的可靠应用
  • 允许最终用户在没有网络访问的情况下创建和修改数据,支持几乎没有连接或没有连接的场景。
  • 跨多个设备同步数据,并在两台设备修改同一记录时检测冲突
  • 限制高延迟或按流量计费的网络使用

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

什么是同步表?

若要访问“/tables”终结点,Azure 移动客户端 SDK 提供 IMobileServiceTable(.NET 客户端 SDK)或 MSTable(iOS 客户端)等接口。 这些 API 直接连接到 Azure 移动应用后端,如果客户端设备没有网络连接,则失败。

为了支持脱机使用,应用应改用 同步表 API,例如 IMobileServiceSyncTable (.NET 客户端 SDK)或 MSSyncTable (iOS 客户端)。 所有相同的CRUD操作(创建、读取、更新、删除)都适用于同步表的API,除非它们从本地存储读取或写入。 在执行任何同步表作之前,必须初始化本地存储。

什么是本地商店?

本地存储是客户端设备上的数据持久性层。 Azure 移动应用客户端 SDK 提供默认的本地存储实现。 在 Windows、Xamarin 和 Android 上,它基于 SQLite。 在 iOS 上,它基于核心数据。

若要在 Windows Phone 或 Microsoft 应用商店上使用基于 SQLite 的实现,需要安装 SQLite 扩展。 有关详细信息,请参阅 通用 Windows 平台:启用脱机同步。Android 和 iOS 设备的操作系统自带 SQLite 版本,因此无需引用您自己的 SQLite 版本。

开发人员还可以实现自己的本地存储功能。 例如,如果要在移动客户端上以加密格式存储数据,则可以定义使用 SQLCipher 进行加密的本地存储。

什么是同步上下文?

同步上下文与移动客户端对象(例如IMobileServiceClientMSClient)相关联,并跟踪与同步表所做的更改。 同步上下文维护操作队列,这是一个稍后发送到服务器的创建、更新、删除(CUD)操作的有序列表。

本地存储使用初始化方法(例如 IMobileServicesSyncContext.InitializeAsync(localstore)中的 )与同步上下文相关联。

脱机同步的工作原理

使用同步表时,客户端代码控制本地更改何时与 Azure 移动应用后端同步。 在调用推送本地更改之前,不会向后端 发送 任何内容。 同样,仅当调用 拉取 数据时,本地存储才会填充新数据。

  • 推送:推送是同步上下文上的操作,并发送从上次推送后开始的所有 CUD 更改。 请注意,无法仅发送单个表的更改,否则操作可能会被无序发送。 推送将执行对 Azure 移动应用后端的一系列 REST 调用,后者反过来会修改服务器数据库。

  • 拉取:按表执行拉取,可以使用查询进行自定义,以仅检索服务器数据的子集。 然后,Azure 移动客户端 SDK 将生成的数据插入本地存储中。

  • 隐式推送:如果对有挂起本地更新的表执行拉取操作,那么拉取会首先在同步上下文中执行 push()。 此推送有助于最大程度地减少已排队的更改与服务器中的新数据之间的冲突。

  • 增量同步:拉取操作的第一个参数是仅在客户端上使用的 查询名称。 如果使用非 null 查询名称,Azure 移动 SDK 将执行 增量同步。每次拉取操作返回一组结果时,该结果集中的最新 updatedAt 时间戳都存储在 SDK 本地系统表中。 后续拉取操作仅检索该时间戳之后的记录。

    若要使用增量同步,服务器必须返回有意义的 updatedAt 值,并且还必须支持按此字段排序。 但是,由于 SDK 在 updatedAt 字段中添加了自己的排序机制,无法使用带有其自身 orderBy 子句的 pull 查询。

    查询名称可以是你选择的任何字符串,但它对于应用中的每个逻辑查询必须是唯一的。 否则,不同的拉取操作可能会覆盖相同的增量同步时间戳,查询可能会返回错误的结果。

    如果查询具有参数,则创建唯一查询名称的一种方法是合并参数值。 例如,如果要筛选 userid,则查询名称可能如下所示(在 C# 中):

      await todoTable.PullAsync("todoItems" + userid,
          syncTable.Where(u => u.UserId == userid));
    

    如果要选择退出增量同步,请将 null 作为查询 ID 传递。 在这种情况下,每次调用 PullAsync时都会检索所有记录,这可能效率低下。

  • 清除:您可以使用IMobileServiceSyncTable.PurgeAsync来清除本地存储的内容。 可能需要进行数据清理,如果客户端数据库中存在过时数据,或者如果您想放弃所有待处理的更改。

    清除会移除本地存储中的表。 如果存在等待与服务器数据库同步的操作,除非设置了 强制清除 参数,否则清除将引发异常。

    例如,客户端上的过时数据,假设在“待办事项列表”示例中,Device1 仅提取未完成的项目。 另一台设备在服务器上将待办事项“购买牛奶”标记为已完成。 但是,由于Device1只会拉取未标记为已完成的项目,它在本地存储中仍然有“购买牛奶”这个待办事项。 清除会移除此过时项目。

后续步骤