无网环境的离线优先架构与数据同步机制

地铁里没信号是常态。如果在没网的时候,用户点击"发布评论"直接弹一个"网络异常",他们的第一反应绝对是卸载。现代应用架构的标准是"离线优先":无论有没有网,操作立刻在本地完成,剩下的交给后台悄悄同步。

把本地数据库当成唯一真相

传统的写法是:点击发布 -> 转圈圈 -> 发请求 -> 成功 -> 把数据加进 UI 数组。这套逻辑在弱网下必死无疑。

离线优先的核心原则是:UI 永远只认本地数据,网络请求只是后台的异步动作。

用户在输入框敲完字,点击发布:

  1. 立刻往本地的 RDB(关系型数据库)里插入一条记录,状态标记为 待同步。

  2. UI 监听数据库的变化,立刻刷新列表,显示刚刚发布的内容。

  3. 触发后台同步任务,去跟服务器交互。

用户根本感觉不到网络的存在,体验极度丝滑。

设计可靠的消息队列

我们不能直接盲发请求,必须建立一个本地同步队列表。

sql

复制代码
CREATE TABLE IF NOT EXISTS sync_queue (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  action_type TEXT, -- 如 INSERT, UPDATE, DELETE
  payload TEXT,     -- 序列化后的 JSON 数据
  retry_count INTEGER DEFAULT 0,
  created_at INTEGER
);

当网络恢复时,后台任务从队列里按顺序取出操作,批量发送给服务器。如果发送成功,就删掉队列记录,并更新业务表的状态为 已同步。如果失败,就增加 retry_count。

并发控制的警示

在触发同步时,必须加锁。如果用户不停地在操作,而每一次操作都触发一次同步任务,服务器会被你的并发请求打爆。

typescript

复制代码
let isSyncing = false;

async function triggerSync() {
  if (isSyncing) return; // 锁住,避免并发
  isSyncing = true;
  
  try {
    // 取出队列数据发送请求...
  } finally {
    isSyncing = false;
    // 如果还有积压数据,继续下一轮
    checkAndSyncNext(); 
  }
}

网络状态监听与幂等性防御

必须利用 @ohos.net.connection 监听系统的网络事件。一旦触发 netAvailable,立刻唤醒同步引擎。

这里有一个极度危险的边缘场景:客户端发出了请求,服务器处理成功了,但在返回响应时网络断了。客户端认为失败,下次重试时会再次发送同样的请求,导致服务器出现两条重复的数据。

解决办法: 在客户端生成唯一的业务 UUID,跟请求一起发给服务器。服务器收到请求后,先查库里有没有这个 UUID,有就直接丢弃,没有才执行落库。这就叫接口幂等性,是离线架构的生命线。

写一个极简的备忘录应用。开启飞行模式,疯狂添加十条备忘录。然后关闭飞行模式,观察备忘录是怎么在后台自动同步到本地服务端的,并查一下数据库里的状态变化。