移動(dòng)端與服務(wù)器端數(shù)據(jù)庫同步

本文為轉(zhuǎn)載文章,查看原文請(qǐng)點(diǎn)擊以下鏈接。

  1. 時(shí)間戳
  2. 更新狀態(tài)(本文未提及)
    更新狀態(tài)包括添加,修改,刪除等等,明確告訴另一端具體是做哪一種更新。
  3. 記錄數(shù)據(jù)更改記錄的表(本文未提及)
    按我理解,時(shí)間戳與更新狀態(tài)這兩個(gè)字段可以放在需要同步的目標(biāo)表里,也可新建一個(gè)更改記錄
    表,主要字段包括時(shí)間戳,更新狀態(tài),待同步數(shù)據(jù)的主鍵(如guid).
    不知這種理解是否正確。

以下是正文:

數(shù)據(jù)庫同步滿足以下幾個(gè)需求:

  1. 同步時(shí)雙向傳輸數(shù)據(jù)最小化。雙向即,服務(wù)器端更新同步到移動(dòng)端,和移動(dòng)端更新同步到服務(wù)器。每次只傳輸兩端差異數(shù)據(jù)。

  2. 支持離線。支持離線本身是一種好的用戶體驗(yàn),而它帶來的一個(gè)其他的好處是每次移動(dòng)端數(shù)據(jù)庫查詢僅需查詢本地?cái)?shù)據(jù)庫,這樣就避免了過多的服務(wù)器端查詢。本地?cái)?shù)據(jù)庫減少了很多服務(wù)器的壓力,當(dāng)然也給用戶省了流量。數(shù)據(jù)庫更新操作也是如此,僅更新本地?cái)?shù)據(jù)庫,然后在適當(dāng)?shù)臅r(shí)機(jī)與服務(wù)器端進(jìn)行同步。更進(jìn)一步的說,移動(dòng)端查詢和更新數(shù)據(jù)只跟本地?cái)?shù)據(jù)庫打交道。

  3. 沖突解決。如果一個(gè)用戶帳號(hào)在多個(gè)移動(dòng)端進(jìn)行離線使用,勢(shì)必會(huì)產(chǎn)生數(shù)據(jù)沖突。

設(shè)計(jì)的關(guān)鍵在于數(shù)據(jù)模型的設(shè)計(jì),和同步算法。以下是我的想法。

下面是對(duì)象類代碼,對(duì)應(yīng)數(shù)據(jù)庫的表字段。
服務(wù)器端設(shè)計(jì):

public abstract class ServerBaseModel {
 
    public long userId; /* Global unique user id */
 
    public long id; /* Model id. Unique for user */
 
    public long lastmodified; /* Last modified server time stamp */
 
    public boolean deleted; /* delete flag */
 
}

移動(dòng)端設(shè)計(jì):

public abstract class ClientBaseModel {
 
    public long userId; /* Global unique user id */
 
    public long id; /* Model id. Unique for user */
 
    public long lastmodified; /* Last modified server time stamp */
 
    public boolean deleted; /* delete flag */
 
    public boolean dirty; /* Local dirty flag */
}

首先是如何選擇表的主鍵id

  1. 使用auto increment主鍵?不行!根據(jù)前面支持離線的需求,id應(yīng)該在移動(dòng)端就已經(jīng)生成。如果使用auto increment在同一個(gè)用戶帳號(hào)的情況下只可以做到單個(gè)移動(dòng)端的唯一性,無法保證多個(gè)移動(dòng)端的唯一性,更加不能保證服務(wù)器端全局的唯一性。

  2. 使用UUID作為主鍵?可行!每一條數(shù)據(jù)在移動(dòng)端創(chuàng)建時(shí)即為之生成UUID。這樣基本可以保證服務(wù)器端全局的唯一性。對(duì)于使用UUID作為主鍵好不好的討論很多,大家可以另行參考。

  3. 我的方案。使用userId和一個(gè)用戶唯一的model id作為聯(lián)合主鍵。model id需要保證在同一userId下唯一,這樣再加上userId使得數(shù)據(jù)全局唯一。問題是如何選擇model id?一個(gè)比較可行但是不能保證完全沒有重復(fù)的是時(shí)間戳。

  4. 還有其他更好的主鍵方案嗎?

接下來是如何判斷服務(wù)器端數(shù)據(jù)已經(jīng)更新

每一條數(shù)據(jù)存儲(chǔ)一個(gè)last modified時(shí)間戳。這個(gè)時(shí)間戳是服務(wù)器端的時(shí)間。同一條數(shù)據(jù)如果移動(dòng)端的lastmodified小于服務(wù)器端的lastmodified就可以判斷數(shù)據(jù)已經(jīng)更新。

移動(dòng)端數(shù)據(jù)更新

移動(dòng)端數(shù)據(jù)庫增加一個(gè)dirty標(biāo)志,dirty標(biāo)志表示本地新增或者修改的數(shù)據(jù),這些數(shù)據(jù)會(huì)在下一次同步時(shí)上傳至服務(wù)器。

如何處理數(shù)據(jù)刪除

根據(jù)前面last modified和dirty字段的設(shè)計(jì),整個(gè)數(shù)據(jù)模型是一個(gè)增量式的。數(shù)據(jù)只允許新增和更新,所以這里增加一個(gè)deleted標(biāo)志表示數(shù)據(jù)是否已經(jīng)被刪除。

以上介紹完我的移動(dòng)端和服務(wù)器端數(shù)據(jù)庫同步的數(shù)據(jù)模型設(shè)計(jì),接下來講講同步算法。
同步算法:
服務(wù)器端向移動(dòng)端同步

  1. 獲得移動(dòng)端最大的last modified,發(fā)送至服務(wù)器端。
  2. 服務(wù)器端查詢所有l(wèi)ast modified值比移動(dòng)端最大last modified的數(shù)據(jù),返回至移動(dòng)端。
  3. 移動(dòng)端更新本地?cái)?shù)據(jù)庫

移動(dòng)端向服務(wù)器端同步

  1. 獲得所有的dirty數(shù)據(jù),發(fā)送至服務(wù)器端。
  2. 服務(wù)器端處理dirty數(shù)據(jù),返回更新的數(shù)據(jù)的新的last modified。
  3. 移動(dòng)端更新last modified,并且清楚dirty標(biāo)志。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容