MySQL(十六)】更新丟失 解決方案

一個比較見的業務場景,先從表裏讀一條數據的一列,然後在內存中計算該列的新值,最後再update新值到表裏:

select data from table where id = xxx; // db

newdate = data + 1; // 內存

update table set data = newdata where id = xxx; // db

這樣的三條語句,如果不加事務,可能會有更新丟失的問題。就是多個事務併發修改同一行數據時,讀到了相同的值,然後分別更新,那麼就會丟失前一次更新;

爲啥要分三條?直接update set data = data + 1貌似就行?

這裏的+1只是示例,實際上這個1可能需要根據一些特定的業務邏輯計算出來,所以必須要先讀到內存才能計算到新值;

怎麼解決更新丟失問題?

這裏介紹兩種方案:

1.使用事務+鎖定讀

begin;

select data from table where id = xxx for update; // db

newdate = data + 1; // 內存

update table set data = newdata where id = xxx; // db

commit;

這裏首先使用了begin語法,將上述三個步驟放入到事務中,並且讀取時使用了for update的鎖定讀方式,這樣一旦讀到了數據,那麼就會加X鎖,別的事務便無法讀該行數據或者修改該行數據了。

2.不使用事務,cas更新

// for loop begin
select data from table where id = xxx; // db

newdate = olddata + 1;// 內存

update table set data = newdata where id = xxx and data = olddata; // db
// for loop end

這個方案不需要事務,但是在update時,加上了cas的判斷,整套邏輯需要放在循環中完成,不斷cas嘗試直到更新成功,需要業務邏輯來處理cas更新,並且可能需要設置最大重試次數,防止一直自旋;

貌似在高併發場景下,使用方案一更好些,畢竟方案二衝突的概率比較大,一直重複select update也會影響性能;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章