當我們要對乙個資料庫中的一條資料進行修改的時候,為了避免同時被其他人修改,最好的辦法就是直接對該資料進行加鎖以防止併發,這種借助資料庫鎖機制在修改資料之前先鎖定,再修改的方式被稱之為悲觀併發控制。
悲觀鎖,它指的是對資料被外界(包括本系統當前的其他事務,以及來自外部系統的事務處理)修改持保守態度(悲觀),因此,在整個資料處理過程中,將資料處於鎖定狀態。 悲觀鎖的實現,往往依靠資料庫提供的鎖機制 。
悲觀併發控制主要應用於資料爭用激烈的環境,以及發生併發衝突時使用鎖保護資料的成本要低於回滾事務的成本環境
資料庫中,悲觀鎖的流程如下
•在對任何記錄進行修改之前,先嘗試為該記錄加上排他鎖
•如果加鎖失敗,說明該記錄正在被修改,那麼當前查詢可能要等待或丟擲異常
•如果成功加鎖,則就可以對記錄做修改,事務完成後就會解鎖
•其間如果有其他對該記錄做修改或加排他鎖的操作,都會等待我們解鎖或直接丟擲異常
//開始事務
begin;
select status from t_goods where id=1 for update;
//根據商品資訊生成訂單
insert into t_orders (id,goods_id) values (null,1);
//修改商品status為2
update t_goods set status=2;
// 提交事務
commit;
以上查詢語句中,使用了select…for update方式,通過開啟排他鎖的方式實現了悲觀鎖。則相應的記錄被鎖定,其他事務必須等本次事務提交之後才能夠執行
我們使用select … for update會把資料給鎖定,不過我們需要注意一些鎖的級別,mysql innodb預設行級鎖。行級鎖都是基於索引的,如果一條sql用不到索引是不會使用行級鎖的,會使用表級鎖把整張表鎖住。
注意:在不通過索引條件查詢的時候,innodb使用的是表鎖,而不是行鎖。這點需要特別注意
為資料處理的安全提供了保證
效率上,由於處理加鎖的機制會讓資料庫產生額外開銷,增加產生死鎖機會
在唯讀型事務中由於不會產生衝突,也沒必要使用鎖,這樣會增加系統負載,降低並行性
樂觀鎖相對悲觀鎖而言,它認為資料一般情況下不會造成衝突,所以在資料進行提交更新的時候,才會正式對資料的衝突與否進行檢測,如果發現衝突了,則讓返回錯誤資訊,讓使用者決定如何去做。
利用資料版本號(version)機制是樂觀鎖最常用的一種實現方式。一般通過為資料庫表增加乙個數字型別的 「version」 字段,當讀取資料時,將version欄位的值一同讀出,資料每更新一次,對此version值+1。當我們提交更新的時候,判斷資料庫表對應記錄的當前版本資訊與第一次取出來的version值進行比對,如果資料庫表當前版本號與第一次取出來的version值相等,則予以更新,否則認為是過期資料,返回更新失敗。
既然可以用version,那還可以使用時間戳字段,該方法同樣是在表中增加乙個時間戳字段,和上面的version類似,也是在更新提交的時候檢查當前資料庫中資料的時間戳和自己更新前取到的時間戳進行對比,如果一致則ok,否則就是版本衝突。
// 仍挑選以庫存數作為樂觀鎖
//step1: 查詢出商品資訊
select (inventory) from items where id=100;
//step2: 根據商品資訊生成訂單
insert into orders(id,item_id) values(null,100);
//step3: 修改商品的庫存
update items set inventory=inventory-1 where id=100 and inventory-1>0;
樂觀鎖:
讀多寫少的場景,如果出現大量的寫入操作,資料發生衝突的可能性就會增大,為了保證資料的一致性,應用層需要不斷的重新獲取資料,這樣會增加大量的查詢操作,降低了系統的吞吐量。 比如 :秒殺活動
悲觀鎖:
比較適合寫入操作比較頻繁的場景,如果出現大量的讀取操作,每次讀取的時候都會進行加鎖,這樣會增加大量的鎖的開銷,降低了系統的吞吐量。 比如 :下單操作
樂觀鎖:
樂觀鎖的特點先進行業務操作,不到萬不得已不去拿鎖。即「樂觀」的認為拿鎖多半是會成功的,因此在進行完業務操作需要實際更新資料的最後一步再去拿一下鎖就好。
悲觀鎖:
悲觀鎖的特點是先獲取鎖,再進行業務操作,即「悲觀」的認為獲取鎖是非常有可能失敗的,因此要先確保獲取鎖成功再進行業務操作。通常所說的「一鎖二查三更新」即指的是使用悲觀鎖。
深度理解樂觀鎖與悲觀鎖
public int updateentry long id for update id 2 修改記錄內容,根據計算修改entry記錄的屬性 string name generatorname entry entry.setname name 3 update操作 int count update ...
悲觀鎖與樂觀鎖的理解
悲觀鎖 總是假設發生最壞的情況,就是每次去拿資料的時候都認為別人會修改,所以每次在拿資料的時候都會上鎖,這樣別人想拿這個資料就會阻塞直到它拿到鎖 共享資源每次只給乙個執行緒使用,其它執行緒阻塞,用完後再把資源轉讓給其它執行緒 傳統的關係型資料庫裡邊就用到了很多這種鎖機制,比如行鎖,表鎖等,讀鎖,寫鎖...
樂觀鎖與悲觀鎖的理解
不管是悲觀鎖還是樂觀鎖,主要作用就是對共享資源上鎖,防止多執行緒訪問產生的執行緒安全問題。鎖處理的是修改資料問題 更新資料問題 悲觀鎖 假設資料修改一定會出現執行緒安全問題,訪問時申請對資源的鎖,其他使用者只能阻塞等待。樂觀鎖 假設資料修改一般不會出現衝突,只有在資料提交的時候才會對資料衝突與否進行...