一個業務偶然遇到了并發寫操作互相覆寫的問題。直覺的想法是能不能加鎖?看了一下雲開發資料庫沒有提供鎖的接口(當然資料庫自己寫操作的時候肯定實作了自己的鎖)。
那很自然的就想到了,用inc操作維護記錄的版本号,加樂觀鎖來避免誤寫。不過這樣的代價也很大,update操作不能用快速的doc操作來定位記錄,而必須用條件查詢方式來定位記錄,并發寫的時候還有可能需要進行多次的重試擷取版本并寫入直到自己排上隊,那要重試幾次合适呢?還是得考慮下怎麼利用資料庫自己的鎖機制來避免覆寫。
一個解決辦法是把資料放到數組裡面,更新資料的時候用push或者unshift來插入資料,這樣即使并發寫也不會互相寫覆寫,但是如果是相同的資料重複寫入的話可能數組裡面出現重複元素的問題,可能需要處理額外的去重邏輯。
如果想要自動去重,也可以用哈希對象來管理要寫入的資料(資料寫到key,value如果沒有特别需要可以寫true或者1之類的簡單類型。),然後在用update語句的字段set能力來實作并發更新記錄的時候互相不覆寫:
function test(i){
var answer={};
answer["answer"+i] = _.set(1);
return coll.doc(uid).update({answer:answer})
}
複制
嘗試一下效果:
var n=100,p=[];
for(var i=0;i<n;i++){
p.push(test(i))
}
Promise.all(p).then(res=>{
coll.doc(uid).get().then(res=>{
console.log(JSON.stringify(res));
})
})
複制
如果重複的key寫入相同的資料,會得到{updated:0}的結果,并不會影響已經寫入的資料。
當然如果需要進一步處理重複寫入邏輯,也可以吧_.set(1) 改成 _.inc(1) 來記錄同一個key被重複寫入了多少次。
要留意的是并發數n過大的時候會出現逾時。