Mysql鎖機制簡單了解一下
來自專欄 Java面試通關手冊
歷史文章推薦:
可能是最漂亮的Spring事務管理詳解
面試中關於Java虛擬機(jvm)的問題看這篇就夠了
Java NIO 概覽
關於分散式計算的一些概念
一 鎖分類(按照鎖的粒度分類)
Mysql為了解決並發、數據安全的問題,使用了鎖機制。
可以按照鎖的粒度把資料庫鎖分為表級鎖和行級鎖。
- 表級鎖Mysql中鎖定 粒度最大 的一種鎖,對當前操作的整張表加鎖,實現簡單 ,資源消耗也比較少,加鎖快,不會出現死鎖 。其鎖定粒度最大,觸發鎖衝突的概率最高,並發度最低,MyISAM和 InnoDB引擎都支持表級鎖。
- 行級鎖Mysql中鎖定 粒度最小 的一種鎖,只針對當前操作的行進行加鎖。 行級鎖能大大減少資料庫操作的衝突。其加鎖粒度最小,並發度高,但加鎖的開銷也最大,加鎖慢,會出現死鎖。 InnoDB支持的行級鎖,包括如下幾種。1. Record Lock: 對索引項加鎖,鎖定符合條件的行。其他事務不能修改 和刪除加鎖項;
2.Gap Lock: 對索引項之間的「間隙」加鎖,鎖定記錄的範圍(對第一條記錄前的間隙或最後一條將記錄後的間隙加鎖),不包含索引項本身。其他事務不能在鎖範圍內插入數據,這樣就防止了別的事務新增幻影行。
3.Next-key Lock: 鎖定索引項本身和索引範圍。即Record Lock和Gap Lock的結合。可解決幻讀問題。
雖然使用行級索具有粒度小、並發度高等特點,但是表級鎖有時候也是非常必要的:
- 事務更新大表中的大部分數據直接使用表級鎖效率更高;
- 事務比較複雜,使用行級索很可能引起死鎖導致回滾。
二 鎖分類(按照是否可寫分類)
表級鎖和行級鎖可以進一步劃分為共享鎖(s)和排他鎖(X)。
- 共享鎖(s)共享鎖(Share Locks,簡記為S)又被稱為讀鎖,其他用戶可以並發讀取數據,可以再加共享鎖,但任何事務都不能獲取數據上的排他鎖,直到已經釋放所有共享鎖。
若事務T對數據對象A加上S鎖,則事務T只能讀A;其他事務只能再對A加S鎖,而不能加X鎖,直到T釋放A上的S鎖。這就保證了其他事務可以讀A,但在T釋放A上的S鎖之前不能對A做任何修改。
- 排他鎖(X)排它鎖((Exclusive lock,簡記為X鎖))又稱為寫鎖,若事務T對數據對象A加上X鎖,則只允許T讀取和修改A,其它任何事務都不能再對A加任何類型的鎖,直到T釋放A上的鎖。它防止任何其它事務獲取資源上的鎖,直到在事務的末尾將資源上的原始鎖釋放為止。在更新操作(INSERT、UPDATE 或 DELETE)過程中始終應用排它鎖。
兩者之間的區別:
- 共享鎖(S鎖):如果事務T對數據A加上共享鎖後,則其他事務只能對A再加共享鎖,不 能加排他鎖。獲取共享鎖的事務只能讀數據,不能修改數據。
- 排他鎖(X鎖):如果事務T對數據A加上排他鎖後,則其他事務不能再對A加任何類型的封鎖。獲取排他鎖的事務既能讀數據,又能修改數據。
三 另外兩個表級鎖:IS和IX
當一個事務需要給自己需要的某個資源加鎖的時候,如果遇到一個共享鎖正鎖定著自己需要的資源的時候,自己可以再加一個共享鎖,不過不能加排他鎖。但是,如果遇到自己需要鎖定的資源已經被一個排他鎖佔有之後,則只能等待該鎖定釋放資源之後自己才能獲取鎖定資源並添加自己的鎖定。
意向鎖的作用就是當一個事務在需要獲取資源鎖定的時候,如果遇到自己需要的資源已經被排他鎖佔用的時候,該事務可以需要鎖定行的表上面添加一個合適的意向鎖。如果自己需要一個共享鎖,那麼就在表上面添加一個意向共享鎖。而如果自己需要的是某行(或者某些行)上面添加一個排他鎖的話,則先在表上面添加一個意向排他鎖。意向共享鎖可以同時並存多個,但是意向排他鎖同時只能有一個存在。
InnoDB另外的兩個表級鎖:
- 意向共享鎖(IS): 表示事務準備給數據行加入共享鎖,事務在一個數據行加共享鎖前必須先取得該表的IS鎖。
- 意向排他鎖(IX): 表示事務準備給數據行加入排他鎖,事務在一個數據行加排他鎖前必須先取得該表的IX鎖。
注意:
- 這裡的意向鎖是表級鎖,表示的是一種意向,僅僅表示事務正在讀或寫某一行記錄,在真正加行鎖時才會判斷是否衝突。意向鎖是InnoDB自動加的,不需要用戶干預。
- IX,IS是表級鎖,不會和行級的X,S鎖發生衝突,只會和表級的X,S發生衝突。
InnoDB的鎖機制兼容情況如下:
當一個事務請求的鎖模式與當前的鎖兼容,InnoDB就將請求的鎖授予該事務;反之如果請求不兼容,則該事物就等待鎖釋放。
四 死鎖和避免死鎖
InnoDB的行級鎖是基於索引實現的,如果查詢語句為命中任何索引,那麼InnoDB會使用表級鎖. 此外,InnoDB的行級鎖是針對索引加的鎖,不針對數據記錄,因此即使訪問不同行的記錄,如果使用了相同的索引鍵仍然會出現鎖衝突,還需要注意的是,在通過
SELECT ...LOCK IN SHARE MODE;
或
SELECT ...FOR UPDATE;
使用鎖的時候,如果表沒有定義任何索引,那麼InnoDB會創建一個隱藏的聚簇索引並使用這個索引來加記錄鎖。
此外,不同於MyISAM總是一次性獲得所需的全部鎖,InnoDB的鎖是逐步獲得的,當兩個事務都需要獲得對方持有的鎖,導致雙方都在等待,這就產生了死鎖。 發生死鎖後,InnoDB一般都可以檢測到,並使一個事務釋放鎖回退,另一個則可以獲取鎖完成事務,我們可以採取以上方式避免死鎖:
- 通過表級鎖來減少死鎖產生的概率;
- 多個程序盡量約定以相同的順序訪問表(這也是解決並發理論中哲學家就餐問題的一種思路);
- 同一個事務儘可能做到一次鎖定所需要的所有資源。
五 總結與補充
MyISAM和InnoDB存儲引擎使用的鎖:
- MyISAM採用表級鎖(table-level locking)。
- InnoDB支持行級鎖(row-level locking)和表級鎖,默認為行級鎖
表級鎖和行級鎖對比:
- 表級鎖: Mysql中鎖定 粒度最大 的一種鎖,對當前操作的整張表加鎖,實現簡單,資源消耗也比較少,加鎖快,不會出現死鎖。其鎖定粒度最大,觸發鎖衝突的概率最高,並發度最低,MyISAM和 InnoDB引擎都支持表級鎖。
- 行級鎖: Mysql中鎖定 粒度最小 的一種鎖,只針對當前操作的行進行加鎖。 行級鎖能大大減少資料庫操作的衝突。其加鎖粒度最小,並發度高,但加鎖的開銷也最大,加鎖慢,會出現死鎖。
補充:
頁級鎖: MySQL中鎖定粒度介於行級鎖和表級鎖中間的一種鎖。表級鎖速度快,但衝突多,行級鎖衝突少,但速度慢。頁級進行了折衷,一次鎖定相鄰的一組記錄。BDB支持頁級鎖。開銷和加鎖時間界於表鎖和行鎖之間,會出現死鎖。鎖定粒度界於表鎖和行鎖之間,並發度一般。
參考:
《深入淺出MySQL》
《Java工程師修鍊之道》
歡迎關注我的微信公眾號:"Java面試通關手冊"(一個有溫度的微信公眾號,無廣告,單純技術分享,期待與你共同進步,期待與你不期而遇~~~堅持原創,分享美文,分享各種Java學習資源。)
推薦閱讀:
※什麼是最好的oracle sql 開發工具?
※基於mysql的資料庫基本操作(含初始數據寫入sequel pro步驟)
※知識布局-mysql-組內排序
※《深入淺出SQL》學習筆記
※SQL面試,讓你的面試官無fu,ck可說,第17題難倒一片人