在DB操作中,如何避免第一個transaction的修改被第二個transaction覆蓋?
02-02
比如,在mysql中,先創建表:
create table t (id int,val int
);插入數據:insert into t(id,val) values(1,1);然後假如有以下transaction:
-- transaction start transaction;select val into @v from t where id=1;update t set val=(@v+1) from where id=1;commit;
這是一個非常簡單的transaction,首先讀入val的值,然後把這個值加1後寫回。但如果同時有兩個transaction在執行的話,第一個讀入val的值到@v, 然後第二個transaction也執行了這一句,接著第一個transaction執行update,讓val的值變為2。這個時候第二個transaction會用2覆蓋第一個transaction的執行結果。最終結果為2(應該為3才對)。
這個問題的解決方案有兩個:1.使用serializable 的 isolation level。2.存儲一列version欄位,每個transaction都先讀入version的值,然後更新的時候使用where version="先前讀入的值",並改變version的值。請問針對這種問題,有沒有其他標準的解決方案?
這不是標準的悲觀並發鎖和樂觀並發鎖嘛
悲觀就是 我擦肯定有人來搞我,我必須做好一切防備鎖定一切資源
樂觀就是,嘿嘿我估計沒誰來搞我,我先嘗試做著,做到最後發現版本不對大不了拋個異常唄,又死不了人
此外的模型 我。。我也沒用過
第一種方法可以,適用於任何主流資料庫產品,但是副作用也很大。
第二種方法根本就沒解決問題。
針對mysql或者oracle最好用select for update,其他產品應該也有相應的語句。我比較喜歡用第二個方案,連 trans 都不需要:
select val into @v from t where id=1;
update t set val=(@v+1) from where id=1 and val=@v;根據返回更新條數判斷此次操作是否成功,不成功則循環。
也不用增加 version,當然增加 version 適用場景更廣泛一些。這邏輯跟無鎖操作的 cas 思路是一樣的,實際使用出現碰撞的幾率很小。就是事務的隔離級別嘛,Read uncommitted、Read committed、Repeatable read、Serializable
推薦閱讀:
※Mysql在RC隔離級別下是如何實現讀不阻塞的?
※產品DBA、開發DBA、運維DBA的區別?
※如何解決主從資料庫同步延遲問題?
※MYSQL及MySQL WORKBENCH安裝過程遇到的問題及處理方法