鎖機制--事務鎖、樂觀鎖、悲觀鎖
檢視mysql隔離級別:
select @@tx_isolation;
show variables like '%tx_isolation%';
事務的四種隔離級別
set session transaction isolation level 隔離級別
1. read uncommitted : 讀取尚未提交的資料:哪個問題都不能解決 2. read committed:讀取已經提交的資料 :可以解決髒讀 ---- oracle預設 會出現不可重複讀,幻讀 3. repeatable read:重讀讀取:可以解決髒讀和不可重複讀 ---mysql預設的,無法解決幻讀 4. serializable:序列化:可以解決髒讀、不可重複讀和幻讀---相當於鎖表
serializable隔離級別下,所有select語句都會被隱式的轉化為select …lock in share mode.這可能導致,如果有未提交的事務正在修改某些行,所有讀取這些行的select都會被阻塞住。
show variables like '%iso%'
版本控制很強,在設定set global transaction isolation level read committed;
時無法更改當前會話,可以在修改全域性變數後修改會話set session transaction isolation level read committed;
類似重新載入變數
驗證隔離級別操作步驟
開始驗證之前,需要知道,MySQL預設開啟autocommit,預設隔離級別為repeatable read
,MySQL事務的流程為begin ...end
。
在事務執行過程中,採用MVCC解決不可重複讀問題。事務在預設隔離級別下,多版本控制資料庫DML操作。
在模擬實驗時需設定autocommit=off
,方便模擬
順序 | 事務1 | 事務2 |
---|---|---|
1 | begin; | |
2 | begin; | |
3 | select * from sakila2.actor1 where actor_id=2; | |
4 | select * from sakila2.actor1 where actor_id=2; | |
5 | update sakila2.actor1 set first_name=‘kdd1’ where actor_id=2; | |
6 | commit; | |
7 | select * from sakila2.actor1 where actor_id=2; | |
8 | select * from sakila2.actor1 where actor_id=2; | |
9 | update sakila2.actor1 set first_name=‘kdd1’ where actor_id=2; | |
10 | commit; | |
11 | select * from sakila2.actor1 where actor_id=2; | |
12 | select * from sakila2.actor1 where actor_id=2; | |
13 | end; | |
14 | end; |
樂觀鎖和悲觀鎖
當我們說樂觀鎖和悲觀鎖時,它們的概念和事務鎖(共享鎖、排它鎖)是完全不同的。
樂觀鎖和悲觀鎖是針對應用和資料庫之間的一種取數和鎖定策略。而事務鎖是資料庫為了解決資料庫一致性問題出現的解決方案。這一點很重要。
所謂樂觀鎖,就是利用版本號比較機制,只是在讀資料的時候,將讀到的資料的版本號一起讀出來,當對資料的操作結束後,準備寫資料的時候,再進行一次資料版本號的比較,若版本號沒有變化,即認為資料是一致的,沒有更改,可以直接寫入,若版本號有變化,則認為資料被更新,不能寫入,防止髒寫。版本號一般通過加欄位的方式來實現,可以是自增標識,也可以是時間戳。
說明:以上為操作執行過程簡要描述
說明:如上圖所示,如果更新操作順序執行,則資料的版本(version)依次遞增,不會產生衝突。但是如果發生有不同的業務操作對同一版本的資料進行修改,那麼,先提交的操作(圖中B)會把資料version更新為2,當A在B之後提交更新時發現數據的version已經被修改了,那麼A的更新操作會失敗。
悲觀鎖是以悲觀的態度面對高併發,此時高併發如果採用樂觀鎖會經常導致修改出現等待的情況。
在應用設計和儲存過程開發時,應以最小代價方式選擇樂觀鎖和悲觀鎖。一般b/s環境下,推薦使用樂觀鎖 。
高併發多修改,為什麼使用悲觀鎖?
從下例中可以看出假設只是進行一次修改。
樂觀鎖的操作除了case1其餘均返回錯誤。此時開銷為5次查詢,1次加鎖,1次修改。悲觀鎖只有case1可以執行,其餘均處於等待狀態。此時開銷為,1次查詢,1次加鎖,1次更新。所以使用悲觀鎖開銷更小。
樂觀鎖
case 1 | case 2 | case 3 | case 4 | case 5 |
---|---|---|---|---|
update table set | update table set | update table set | update table set | update table set |
success | failure | failure | failure | failure |
返回資訊 | 下一步操作 | 下一步操作 | 下一步操作 | 下一步操作 |
悲觀鎖
case 1 | case 2 | case 3 | case 4 | case 5 |
---|---|---|---|---|
update table set | 等待操作 | 等待操作 | 等待操作 | 等待操作 |
success | failure | failure | failure | failure |
返回資訊 | 獲取鎖 | 獲取鎖 | 獲取鎖 | 獲取鎖 |