You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android端推送至Azure Mobile Apps数据库时数据变更丢失问题

Android Azure Mobile App Offline Sync Update Issues with Node.js Easy Tables

我来帮你分析下这个离线同步的问题,看起来你已经踩了几个Azure离线同步的常见坑,咱们一步步拆解解决:

首先,解释两种Pull方式的差异

你遇到的两种Pull行为是正常的:

  • 当调用pull(null).get()时,因为没有指定查询ID(第二个参数),Azure会执行全量拉取,直接用远程数据库的内容覆盖本地所有数据,这就是为什么你的本地变更会丢失。
  • 而pull(null, "inventory").get()使用了固定的查询ID,这会触发增量同步——Azure只会拉取自上次同步以来远程更新的数据,不会覆盖本地未同步的变更,所以你的本地修改能保留,但问题出在Push环节没生效。

排查Push失败的核心原因

你的本地变更没同步到线上,大概率是Push操作其实失败了,但你用.get()阻塞调用时没捕获异常,导致没发现问题。先修改代码捕获Push的错误:

try {
    syncContext.push().get();
    Log.d("SyncStatus", "本地变更已成功推送到Azure");
} catch (Exception e) {
    Log.e("SyncError", "Push失败,错误信息:", e);
}

常见的Push失败原因包括:

1. 实体缺少必要字段

Azure Easy Tables依赖几个系统字段来处理更新:

  • id:必须是从本地同步表中获取的原始实体ID(不能是你手动生成的无效ID)
  • __version:乐观并发控制的关键字段,本地更新时这个字段会被标记,同步时Azure会对比这个版本号,如果远程版本更高,会抛出冲突异常
    确保你要更新的Inventory对象是从InventoryTable查询出来的实例,而不是新建的对象,且包含这两个字段。

2. Easy Tables的更新路由被限制

检查你Azure后台的Node.js Easy Tables代码,默认的更新路由应该是这样的:

table.update(function (context) {
    return context.execute();
});

如果这个路由被删除、添加了权限验证(比如未登录用户无法更新),或者自定义逻辑阻止了更新,都会导致Push失败。

3. 乐观并发冲突

如果在你离线修改期间,远程数据库的这条记录已经被其他人修改过,Push时会抛出MobileServicePreconditionFailedException。你需要处理这种冲突,比如合并本地和远程的变更:

try {
    syncContext.push().get();
} catch (ExecutionException e) {
    Throwable cause = e.getCause();
    if (cause instanceof MobileServicePreconditionFailedException) {
        MobileServicePreconditionFailedException conflictEx = (MobileServicePreconditionFailedException) cause;
        Inventory remoteItem = conflictEx.getItem();
        Inventory localItem = conflictEx.getLocalItem();
        
        // 自定义合并逻辑:比如保留本地修改的location字段
        remoteItem.setLocation(localItem.getLocation());
        
        // 更新本地为合并后的版本,重新Push
        DataHolder.getInstance().InventoryTable.update(remoteItem).get();
        syncContext.push().get();
    }
}

正确的同步流程建议

  1. 始终使用带固定查询ID的Pull:比如pull(null, "inventory_sync"),确保增量同步,避免覆盖本地变更
  2. 先Push再Pull:你的顺序是对的,但必须确保Push成功后再执行Pull,否则可能拉取到旧数据覆盖本地
  3. 避免直接用.get()阻塞线程:建议用异步回调或者Coroutines(如果用Kotlin),避免主线程阻塞,同时更容易捕获异常

验证本地同步状态

可以通过以下代码查看是否有待同步的本地操作,确认Push是否真的提交了变更:

List<MobileServiceTableOperation> pendingOps = syncContext.getPendingOperations().get();
Log.d("PendingOps", "待同步操作数量:" + pendingOps.size());

如果Push后这个数量不为0,说明Push确实失败了,需要根据错误信息排查。

内容的提问来源于stack exchange,提问作者Rixium

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:54:38