2013-07-03 39 views
38

Firebase允許更新資源transactionally。據我瞭解,客戶是否會購買向服務器發送請求,說「如果舊值爲X,則創建新值Y」。如果存在爭用,服務器可拒絕來自客戶端的多個更新,直到被接受爲止。Firebase:如何以原子方式更新多個資源?

現在,如果我想要自動更新多個資源呢?

如果第一次更新被接受,然後客戶端在第二次更新被接受之前斷開,會發生什麼情況。有沒有辦法在原子事務中封裝多個更新?如果沒有,是否有解決這個問題的慣用方法?

回答

44

UPDATE

現在已經可以以原子更新多個位置。詳情請參閱this blog post

var mergedUpdate = {}; 
mergedUpdate[ 'users/' + userId + '/widgets/' + widgetId ] = true; 
mergedUpdate[ 'widgets/' + widgetId ] = widgetData; 

var ref = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com/"); 
ref.update(mergedUpdate); 

這並不強制交易數據(如果值是當前X,使其Y),但是這部分可以移動到security rules。例如,如果我們想在同一時間更新兩個計數器,我們可以添加規則如下:

{ 
    "counter1": { 
    ".validate": "newData.val() === (data.val()||0)+1" 
    }, 

    "counter2"1 { 
    ".validate": "newData.val() === (data.val()||0)+1" 
    } 
} 

現在,我們可以嘗試與上述相同的多路徑的更新。如果自從我們上次從服務器讀取這些值後這些值已發生變化,則嘗試將失敗。我們可以檢查if(error.code === 'PERMISSION_DENIED') { ... }以查看失敗是否由於驗證,並相應地重試。

原帖

做到這一點,唯一的辦法是在一個共同的祖先運行的事務。例如,如果要更新/ a/b/c和/ a/x/y,則可以在/ a處運行事務並更改這兩個值。

這種方法的不足之處在於,對於網絡I/O它可能很昂貴,因爲事務內部的所有數據都需要下載併發送回服務器。

您可能要考慮的更復雜但潛在更強大的方法是重構數據,以便存儲編輯的歷史記錄,而不是存儲實際值。例如,如果您要存儲銀行餘額信息,則可以存儲存款和取款的歷史記錄。然後,當你想獲得平衡時,你會回放整個歷史並計算最終平衡。

這種方法的優點是它可以讓你做原子更新。例如,如果您將資金從accountA轉移到accountB,那麼您只需在日誌末尾附加一個元素,指出「從帳戶A轉移到accountB N美元」。附加該單個元素是一個原子操作。

這是我們採用我們的協作文本編輯器Firepad的方法。

+0

感謝您的回答。我在概念上喜歡存儲新的事務而不是更新,但我認爲如果存在查詢實現特性,從性能角度來看這是可行的。重播所有的歷史將是緩慢的。 –

+0

沒有一個(至少現在還沒有),但是我們肯定會看到這將會如何有用!現在,您可以在客戶端實現查詢並將其存儲回Firebase中的「檢查點」(這是Firepad的工作原理),或者您可以將某個node.js或基於Java的服務器作爲Firebase客戶端運行它適合你。 –

+0

嗨! Thanx,但我只是試過,並得到一個錯誤:「第10行:||的左操作數必須是布爾值。」我錯過了什麼嗎?我使用的是Firebase 3.0 ... –

0

還有另一種方式....很繁瑣......,而不是真正的交易...

由於火力地堡允許原子上的數值變化,你可以創建一個鎖或旗語與意義「開始資源x,y和z上的交易「...當然,這不是一個真正的交易,因爲它不會阻止資源,這是鎖定的一部分。我們可以按慣例稱之爲交易。客戶需要知道,當鎖被佔用時,他們不應該改變x,y和z資源....

+2

當兩個客戶端同時請求信號量時,這會中斷。不是一個真正的鎖,所以它不能解決併發問題,只是減少了機會。 –

相關問題