离线场景下的数据同步难题
你有没有遇到过这种情况:外勤人员用笔记本录客户资料,回公司才发现数据没传回主系统,还得手动补录。或者车间设备在无网络环境下运行,等联网上传时发现记录冲突、数据丢失。这些其实都是典型的离线数据库同步问题。
什么是离线数据库同步
简单说,就是当设备无法实时连接主数据库时,先在本地存数据,等网络恢复后再把变更安全地合并回去。关键不在于“存”,而在于“合”——怎么避免重复、冲突和遗漏。
常见实现思路:基于时间戳或版本号
一种基础做法是给每条记录加上最后修改时间或版本号。本地库记录变更后,标记时间戳;联网后,把这段时间内的所有变更上传。主库接收后,再把其他客户端的新数据推下来。
UPDATE users SET name = '张三', version = 5 WHERE id = 1001 AND version = 4;
如果更新失败,说明版本已变,需要先拉取最新数据再重试。这种方式实现简单,适合变化不频繁的场景。
更可靠的方案:操作日志(Change Log)
比起直接同步数据,更好的方式是记录“动作”。比如“用户A在8:30新增了一条订单”,这条操作记入本地日志队列。网络恢复后,逐条提交到服务器执行。
这样做的好处是能追溯每一步变化,也更容易处理冲突。比如两个终端同时修改同一订单,系统可以根据时间或优先级决定采用哪个操作。
实战技巧:用唯一ID避免重复
每个终端生成的数据必须带全局唯一ID(如UUID),不能依赖主库自增ID。否则多个离线设备可能产生相同ID,导致上传时报错。
INSERT INTO orders (id, customer, amount)
VALUES ('uuid-123abc', '李四', 299);
主库按这个ID做幂等处理,即使同一条数据多次上传,也只保存一次。
冲突处理要提前设计
两个销售员同时改同一个客户的电话号码,该听谁的?可以设定规则:以最新时间为准,或提示人工确认。系统层面可以通过“最后写入胜出”(Last Write Wins)或“合并策略”来自动处理。
比如用JSON字段存储历史修改记录,发现问题还能回溯:
{
"phone": "138****1234",
"_history": [
{"by": "user1", "time": "2024-03-10T09:00"},
{"by": "user2", "time": "2024-03-10T09:05"}
]
}
轻量工具推荐
对于小团队或单机应用,SQLite + 自定义同步逻辑就够用。如果想省事,可以用现成方案,比如:
- PouchDB + CouchDB:专为离线同步设计,支持自动冲突检测
- Supabase:开源替代Firebase,提供离线优先的客户端SDK
- 自建MQTT+本地缓存:适合工业设备类场景,网络一通就发消息
别忘了反向同步
很多人只想着“上传本地数据”,却忘了主库的新信息也要下推。比如价格表更新了,得同步到各个离线终端,不然开单还是旧价。所以同步一定是双向的,定时轮询或靠消息通知都可以。