
1) 【一句话结论】:采用本地SQLite存储离线消息,通过增量同步(仅同步新增/修改记录)减少网络流量,结合时间戳/版本号解决冲突,确保数据一致性与快速同步体验。
2) 【原理/概念讲解】:
离线缓存是指无网络时,数据先存本地(如SQLite),网络恢复后同步。增量同步仅同步本地有变化(新增/修改)的记录,避免全量传输。冲突解决用于两端同时修改同一记录,通过时间戳(最新修改时间)或版本号判断,比如最后写入的记录覆盖旧记录(最后写入者胜)。类比:本地数据库像用户的“个人备忘录”,增量同步像“只更新备忘录中新增或修改的条目,而不是重写整本备忘录”,冲突解决像“两个朋友同时修改同一张纸条,最后写的覆盖之前的”。
3) 【对比与适用场景】:
全量同步 vs 增量同步(表格):
| 方案 | 定义 | 特性 | 使用场景 | 注意点 |
|---|---|---|---|---|
| 全量同步 | 每次网络恢复时,将所有本地数据上传至服务器 | 需要传输全部数据,流量大 | 数据量小,网络稳定 | 网络差时同步慢,用户体验差 |
| 增量同步 | 仅同步本地有变化(新增/修改)的记录 | 流量小,同步快 | 数据量大,网络不稳定 | 需要维护本地与服务器数据版本,冲突处理复杂 |
冲突解决策略(对比):
| 策略 | 原理 | 适用场景 | 优缺点 |
|---|---|---|---|
| 最后写入者胜(LWW) | 服务器记录最后修改时间,本地记录时间戳,时间晚的覆盖 | 实时性要求高,数据更新频率低 | 简单,但可能丢失部分修改(如同时修改但时间差小) |
| 时间戳比较(TS Compare) | 比较两端记录的时间戳,晚的覆盖 | 数据更新频率中等 | 更精确,但需要精确时间同步 |
| 服务器端仲裁 | 服务器存储所有修改历史,根据历史判断 | 数据更新冲突多,需要权威仲裁 | 依赖服务器,延迟高 |
4) 【示例】:
CREATE TABLE messages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
content TEXT NOT NULL,
sender_id INTEGER NOT NULL,
receiver_id INTEGER NOT NULL,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
sync_status INTEGER DEFAULT 0, -- 0:未同步, 1:已同步
version INTEGER DEFAULT 1 -- 数据版本号,用于冲突检测
);
function syncOfflineData() {
if (isNetworkAvailable()) {
// 获取本地未同步的增量数据
local_unsynced = SELECT * FROM messages WHERE sync_status = 0;
// 构建请求:包含id, content, timestamp, version
request = buildSyncRequest(local_unsynced);
// 发送请求到服务器
send(request);
// 更新本地数据为已同步
UPDATE messages SET sync_status = 1 WHERE id IN (local_unsynced.id);
}
}
5) 【面试口播版答案】:
(约90秒)
“面试官您好,针对离线消息同步,我的方案是:首先用SQLite本地存储消息数据,设计消息表包含id、内容、发送者/接收者、时间戳、同步状态、版本号等字段。同步策略采用增量同步,只上传本地未同步的记录,减少网络流量。冲突解决采用时间戳比较,即比较两端记录的最后修改时间,时间晚的记录覆盖旧记录。具体流程是:无网络时,消息先存本地;网络恢复后,客户端检查本地未同步数据,发送增量请求到服务器;服务器根据时间戳判断冲突,处理后再同步回客户端。这样既能保证数据一致性,又能提升用户体验,避免全量同步的延迟和流量问题。”
6) 【追问清单】:
7) 【常见坑/雷区】: