在設計時我要滿足以下幾個需求:
1. 同步時雙向傳輸資料最小化。雙向即,伺服器端更新同步到移動端,和移動端更新同步到伺服器。每次隻傳輸兩端差異資料。
2. 支援離線。支援離線本身是一種好的使用者體驗,而它帶來的一個其他的好處是每次移動端資料庫查詢僅需查詢本地資料庫,這樣就避免了過多的伺服器端查詢。本地資料庫減少了很多伺服器的壓力,當然也給使用者省了流量。資料庫更新操作也是如此,僅更新本地資料庫,然後在适當的時機與伺服器端進行同步。更進一步的說,移動端查詢和更新資料隻跟本地資料庫打交道。
3. 沖突解決。如果一個使用者帳号在多個移動端進行離線使用,勢必會産生資料沖突。
設計的關鍵在于資料模型的設計,和同步算法。以下是我的想法。
下面是對象類代碼,對應資料庫的表字段。
伺服器端設計:
public abstract class serverbasemodel {
public long userid; /* global unique user id */
public long id; /* model id. unique for user */
public boolean deleted; /* delete flag */
}
移動端設計:
public abstract class clientbasemodel {
public long userid; <span style="font-family: arial, helvetica, sans-serif;">/* global unique user id */</span>
public long lastmodified; /* last modified server time stamp */
public boolean dirty; /* local dirty flag */
分析:
首先是如何選擇表的主鍵id
1. 使用auto increment主鍵?不行!根據前面支援離線的需求,id應該在移動端就已經生成。如果使用auto increment在同一個使用者帳号的情況下隻可以做到單個移動端的唯一性,無法保證多個移動端的唯一性,更加不能保證伺服器端全局的唯一性。
2. 使用uuid作為主鍵?可行!每一條資料在移動端建立時即為之生成uuid。這樣基本可以保證伺服器端全局的唯一性。對于使用uuid作為主鍵好不好的讨論很多,大家可以另行參考。
3. 我的方案。使用userid和一個使用者唯一的model id作為聯合主鍵。model id需要保證在同一userid下唯一,這樣再加上userid使得資料全局唯一。問題是如何選擇model id?一個比較可行但是不能保證完全沒有重複的是時間戳。
4. 還有其他更好的主鍵方案嗎?
接下來是如何判斷伺服器端資料已經更新
每一條資料存儲一個last modified時間戳。這個時間戳是伺服器端的時間。同一條資料如果移動端的lastmodified小于伺服器端的lastmodified就可以判斷資料已經更新。
移動端資料更新
移動端資料庫增加一個dirty标志,dirty标志表示本地新增或者修改的資料,這些資料會在下一次同步時上傳至伺服器。
如何處理資料删除
根據前面last modified和dirty字段的設計,整個資料模型是一個增量式的。資料隻允許新增和更新,是以這裡增加一個deleted标志表示資料是否已經被删除。
以上介紹完我的移動端和伺服器端資料庫同步的資料模型設計,接下來講講詳細同步算法。
不過。。。等等。。。公司年會的節奏,等有時間繼續寫。
同步算法:
1. 伺服器端向移動端同步
2. 移動端向伺服器端同步
android帳号驗證架構
最新内容請見作者的github頁:http://qaseven.github.io/