mysql數據庫怎么設置樂觀鎖?
樂觀鎖與悲觀鎖不同的是,它是一種邏輯上的鎖,而不需要數據庫提供鎖機制來支持
當數據很重要,回滾或重試一次需要很大的開銷時,需要保證操作的ACID性質,此時應該采用悲觀鎖
而當數據對即時的一致性要求不高,重試一次不太影響整體性能時,可以采用樂觀鎖來保證最終一致性,同時有利于提高并發性
通常,樂觀鎖采用版本號/時間戳的形式實現:給數據額外增加一個版本號字段進行控制;更新時,若提交的數據所帶的版本號與當前記錄的版本號一致,則允許變更執行并更新版本號;若不一致,則意味著產生沖突,根據業務需求直接丟棄并返回失敗,或者嘗試合并
在MySQL的實踐中,常見的一種使用樂觀鎖的方法,是在需要使用樂觀鎖的表中,新增一個version字段
例如:
create table product_amount (
id int not null primary key auto_increment,
product_name varchar(64) not null,
selling_amount int not null,
storing_amount int not null,
version int not null
);
當需要更新銷售中的商品數量(selling_amount)時,使用如下的SQL語句:
update product_amount set selling_amount = #{selling_amount}, version = #{new_version} where id=#{id} and version = #{old_version};
若該語句返回1,則表示更新成功;若返回0,則表示前后的version不一致,產生沖突,更新失敗
對于更新倉庫中的商品數據(storing_amount)時,也是同理
不過,這樣為每行記錄都統一設置一個version字段的樂觀鎖方式,存在一個問題:上例中,如果同時需要單獨對selling_amount及storing_amount進行update(兩條SQL語句分別單獨執行),那么后執行的一條會因為先執行的一條更新了version字段而失敗,而這種失敗顯然是沒有必要的,白白浪費了開銷
一種比較好的方式是為每個需要樂觀鎖的字段單獨設置版本號,例如對上例的改造:
create table product_amount (
id int not null primary key auto_increment,
product_name varchar(64) not null,
selling_amount int not null,
selling_version int not null,
storing_amount int not null,
storing_version int not null
);
selling_amount和storing_amount分別擁有自己的樂觀鎖版本號(selling_version和storing_version),更新時分別只關注自己的版本號,這樣就不會因為版本號被其它字段修改而失敗,提高了并發性