侃侃爾雅
TA貢獻(xiàn)1801條經(jīng)驗(yàn) 獲得超16個(gè)贊
并發(fā)更新方式有兩種:
一種是悲觀(guān)并發(fā)(pessimistic?concurrency)。就是先鎖定數(shù)據(jù),再讀取數(shù)據(jù),一致后再更新,然后解鎖。(可能需要在鎖定、讀取數(shù)據(jù)后先和本地?cái)?shù)據(jù)比較,如果不一致先更新本地?cái)?shù)據(jù))。這樣通過(guò)鎖定保證了更新的數(shù)據(jù)是最新的版本。鎖定可以通過(guò)數(shù)據(jù)庫(kù)提供的行鎖定(甚至是表鎖定)功能,或者是根據(jù)自己的業(yè)務(wù)邏輯自己做一個(gè)鎖定表來(lái)處理。
另一種是樂(lè)觀(guān)并發(fā)(optimistic concurrency)。就是不需要用鎖,而是使用版本戳,比如sql server的timestamp類(lèi)型字段。這樣就可以和本地的數(shù)據(jù)的版本進(jìn)行比較,不一致則更新失敗。失敗后需要自己根據(jù)業(yè)務(wù)邏輯來(lái)處理,有三種處理方式,一種是server win,就是以數(shù)據(jù)庫(kù)當(dāng)前狀態(tài)為準(zhǔn),本次更新失敗。第二種是client win,就是忽略版本戳再次提交,覆蓋掉之前的版本。第三種是merge,需要讀最新數(shù)據(jù),根據(jù)業(yè)務(wù)來(lái)和失敗的提交合并,然后在更新數(shù)據(jù)。這里后兩種處理方式在更新的時(shí)候還是可能會(huì)失敗,可能需要根據(jù)業(yè)務(wù)來(lái)設(shè)計(jì)重試的次數(shù),和最終失敗的處理。
悲觀(guān)并發(fā)的邏輯更容易寫(xiě),但是由于鎖定,性能會(huì)降低。樂(lè)觀(guān)并發(fā)需要考慮的情況更多,但是也更靈活。現(xiàn)在一般更多的考慮采用樂(lè)觀(guān)并發(fā)的方式。
像是更新庫(kù)存的業(yè)務(wù),我建議使用樂(lè)觀(guān)并發(fā)(也就是你目前使用的辦法),在失敗處理時(shí)使用merge,就是失敗的時(shí)候先讀最新庫(kù)存,然后根據(jù)業(yè)務(wù)加減,再次提交。這時(shí)仍然可能失敗,要根據(jù)系統(tǒng)的并發(fā)程度來(lái)確定一個(gè)重試次數(shù),比如3次,每次都是先讀最新庫(kù)存,然后根據(jù)業(yè)務(wù)加減,再次提交。如果失敗超過(guò)了重試次數(shù),就放棄這次操作,提示用戶(hù)失敗。
如果再?lài)?yán)格一些,更新庫(kù)存的操作是需要考慮冪等的。就是如果用戶(hù)可以在UI上本應(yīng)該一次提交的地方能夠進(jìn)行多次提交(比如網(wǎng)頁(yè)上刷新提交頁(yè)面),那么多次提交的結(jié)果應(yīng)該和一次提交一致(也就是防止重復(fù)提交)。一般的方法是可提交的頁(yè)面生成時(shí)分配一個(gè)唯一id,提交時(shí)會(huì)同時(shí)提交這個(gè)id,如果提交成功,這個(gè)id就失效了,再次使用這個(gè)id的提交就忽略。
查看完整回答