在DB操作中,如何避免第一個transaction的修改被第二個transaction覆蓋?

比如,在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安裝過程遇到的問題及處理方法

TAG:資料庫 | MySQL | 資料庫設計 |