飞地有用户写作的需求,所以积累了写作和数据同步的技术研究,这是第二篇数据同步,第一篇写作点此进入。
因为产品有草稿箱功能,所以需要多端同步数据。而同步的对象是文章,且不做冲突备份,直接以最新的版本为主,所以对于同步流程减少一定的复杂度。
文章本地数据模型
同步就是拿本地的缓存数据与服务器数据做对比与合并的过程,那么飞地本地的数据模型大概是这样
class Article {
var uuid: String = UUID().uuidString //文章uuid
var time: TimeInterval = Date().timeIntervalSince1970 //文章修改时间戳
var isLocal: Bool = false //是否为本地文章,未保存到服务器草稿箱
var cover: URL? //文章封面图
var title: String? //文章标题
var content: String? //文章内容html
}
-
文章uuid
并非后台生成的数据库自增长id,而是由
用户端
新建写作时生成的36位长度uuid字符串,用于资源上传时与文章关联,后续文章被删除时好清理无引用的资源,如图片。 文章修改时间戳
相当于文章版本号,上面说到文章同步不做冲突备份,直接以最新的版本为主
就是根据时间戳来对比。isLocal
标识是否为本地文章,在准备同步对比数据
与保存本地文章
时都会用到。其它三个可选字段都为文章数据字段,在后面操作中都是直接覆盖值的,并不做内容的冲突。
流程
准备同步对比的数据
可以理解为本地已保存的文章
的简要数据【文章uuid、文章修改的时间戳】,所谓已保存的文章
就是本地文章isLocal=true
的数据
//请求sync接口的简要数据例子
datas: [{
uuid: 'xxx', //文章uuid
time: xxx //文章最新修改的时间戳
}]
删除草稿时需要有网络下才能操作,也就是说删除操作不在同步中处理。
本地新增的文章也不需要传到后台去对比。
同步对比
以上的数据请求sync同步接口,后台接收到数据后和数据库进行对比返回变动数据:
{
deletes: [ uuid ], //服务器根据参数中的uuid查找数据库(草稿箱和文章表)中该文章是否已删除,如果是则放在此key下。
conflicts:[ {object} ], //冲突的数据,根据参数中的uuid与时间戳做对比,如果数据库的时间戳大于传过来的时间戳则代表文章有新的保存,需要把该文章新对象 放在该key下
saves:[ uuid ], //同上,如果数据库的时间戳小于传过来的时间戳则代表该用户端有新的改动,需要把 该文章uuid 放在该key下
adds:[ {object} ] //返回数据库中新增的文章对象
}
本地合并
APP收到以上对比数据后,分别对每个key进行处理
- deletes中的文章会从本地删除
- conflicts中的数据会替换本地的数据
- saves是本地新改动的数据,该key下的数据需要进行第5步操作
- adds中的数据会新增到本地
保存本地文章
本地新增的文章在以上流程中都没有传到服务器上保存,所以最后我们把本地文章isLocal=true
全保存到服务器上。
至此,一次同步流程结束。